From unknown Sat Jun 14 19:44:59 2025 X-Loop: help-debbugs@gnu.org Subject: bug#78586: TeX-make-inline Resent-From: "Paul D. Nelson" Original-Sender: "Debbugs-submit" Resent-CC: bug-auctex@gnu.org Resent-Date: Sun, 25 May 2025 14:03:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: report 78586 X-GNU-PR-Package: auctex X-GNU-PR-Keywords: To: 78586@debbugs.gnu.org X-Debbugs-Original-To: bug-auctex@gnu.org Received: via spool by submit@debbugs.gnu.org id=B.174818173726123 (code B ref -1); Sun, 25 May 2025 14:03:02 +0000 Received: (at submit) by debbugs.gnu.org; 25 May 2025 14:02:17 +0000 Received: from localhost ([127.0.0.1]:46132 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1uJBvc-0006nH-Nq for submit@debbugs.gnu.org; Sun, 25 May 2025 10:02:17 -0400 Received: from lists.gnu.org ([2001:470:142::17]:59304) by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.84_2) (envelope-from ) id 1uJBvY-0006lu-6i for submit@debbugs.gnu.org; Sun, 25 May 2025 10:02:13 -0400 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 1uJBvH-0002Yl-Ls for bug-auctex@gnu.org; Sun, 25 May 2025 10:01:56 -0400 Received: from mail-ej1-x636.google.com ([2a00:1450:4864:20::636]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1uJBvG-000793-0D for bug-auctex@gnu.org; Sun, 25 May 2025 10:01:55 -0400 Received: by mail-ej1-x636.google.com with SMTP id a640c23a62f3a-ad574992fcaso261026466b.1 for ; Sun, 25 May 2025 07:01:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1748181712; x=1748786512; darn=gnu.org; h=mime-version:message-id:date:subject:to:from:from:to:cc:subject :date:message-id:reply-to; bh=kAQk0CAA/VgcEl1FrkJxKqKbFlbFgCr6hr4TtQznZcA=; b=SBaCgrtmLxbCEKNpI9iNRdzeilh7jRE5bjRmsHjsSH+i+OcrsOXxE/nW8LTDkzZIWL A5CitRvBIsm7e6IBIdFMnFSCb0OIQUpPeq0/ZE3h8whaamqrBSUELC7+X/7P1zbpOeVs Ikb2RBwVF6wegP68kjky6KK65YiFsAdAMsO94ge4iAfowXq/laCpQkcaTpEIOvZjZAws Yf6WjkVME7ag+2V7k7uqYyfWaP5WjvwXdkvy0Pknlxl+RQ7T+vG1brNE99NFhchEFuTv NRbuhPK+yVtQlYtwjbrnjj4Ll9/W4UKM+cf5ilARGt1sr6IsfRsoU2odXjNqb814SUCZ TrhA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1748181712; x=1748786512; h=mime-version:message-id:date:subject:to:from:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=kAQk0CAA/VgcEl1FrkJxKqKbFlbFgCr6hr4TtQznZcA=; b=tUy3GB7YrVOPlFR4AAVRtaKJnLoCVFLrbhDkxmcthoyzQk44K760uB0mAQtLIPeks+ HGmJXf0m0kR1kqUPcUj2vXBLgjQxj3eaV3SDo8qdoiubrMGJeGOzMKLEXw0zl8QcJyXw +jobLkOx1pNy9Ty4MKVcPSfTYDKFxuFRmSqZDV7PyxYGQmOxXtZMprVP2LDcLh7FXJrM 9BbcHzzvoy1u4ldxEoY+hRu5G4Gqvo2lHiZSkVMvI8+C7kgNuZa9RLp30AXXlx9Zkgk4 XldtEVWckr1FCtUIaDLhgJJAjfpdsDgJj9uo6yxg7hEV42SNnHmQw71nfFs0QViHYsWr 3XXQ== X-Gm-Message-State: AOJu0Yygn0p9t8c8VKYVdDyK8Xsq6diQmJ2XDUP2nqrovLK8TrR6RBUg Xk9PViBfKjADkBmXiVrjRZZiwVWEFPLvpYXYIMOCOM4Nr2cpFXwZNRqmYONSKQMm X-Gm-Gg: ASbGncsB9jFNzFoQEEgtEf4yf8RCaUBeY8Z1ytN3fLQoQFjnrZ/1CyjIY4B1j01nLmt 3xBAk8JwfPhS4XZ9MyQzDhlXE0xwc4F8ri6w2mPOgiEKmwk7uIJJ43aSyTgw2U3J+BoznBHM29v GxFXnrQNte9bTCeClJ2wF5OmGsBQBujC3lBbSIe0t2+Kq73U2aQIJ4lJLIuAqWl7lAm3NuBbvSd 6nOw6VUbT0uZfqWJfLp57yqpftMVKxGgxYMTtgndJyqvjiqCEQMbyr88JvD2127Fu3nU9VkJe/q Pui8f/YmufKWarjXO2WB6etgbMtznkhCCunklHqWMroZst+lk/Bi6cR6MmaaQMW2T+jOhcir+9M vlZU= X-Google-Smtp-Source: AGHT+IGSlTw6ILExPqOX9+Es9+jXiMTc3Lj0Xs7L+HFxt63T7BUCpwjF4hsdyBgV9PMdS5RW3NmBzA== X-Received: by 2002:a17:906:338d:b0:ad5:6422:4ef4 with SMTP id a640c23a62f3a-ad85b2a49b5mr365846666b.55.1748181711712; Sun, 25 May 2025 07:01:51 -0700 (PDT) Received: from localhost ([185.229.154.237]) by smtp.gmail.com with UTF8SMTPSA id a640c23a62f3a-ad52d4cbe90sm1522729966b.165.2025.05.25.07.01.51 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 25 May 2025 07:01:51 -0700 (PDT) From: "Paul D. Nelson" Date: Sun, 25 May 2025 16:01:50 +0200 Message-ID: MIME-Version: 1.0 Content-Type: text/plain Received-SPF: pass client-ip=2a00:1450:4864:20::636; envelope-from=ultrono@gmail.com; helo=mail-ej1-x636.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Spam-Score: 1.0 (+) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -0.0 (/) Hi Arash and all, We had discussed in an earlier thread (bug#78006) the possibility of adding some of my editing commands to AUCTeX (as standalone commands, without default binds). We could start with this one, discussed a bit in that thread: --8<---------------cut here---------------start------------->8--- (defcustom TeX-make-inline-delims '("$" . "$") "Delimiters for `TeX-make-inline' to surround inline LaTeX math." :type '(radio (const :tag "Dollar ($...$)" ("$" . "$")) (const :tag "Paren (\\(...\\))" ("\\(" . "\\)")) (cons :tag "Custom delimiters" (string :tag "Left") (string :tag "Right")))) (defun TeX-make-inline () "Convert LaTeX display math environment at point to inline math. Removes the enclosing math environment (such as \\[...\\] or \\begin{equation}...\\end{equation}). Replaces it with inline math surrounded by `TeX-make-inline-delims', fitting the result onto one line. Leaves any trailing punctuation outside the math delimiters." (interactive) (when (texmathp) (when (fboundp 'preview-clearout-at-point) (preview-clearout-at-point)) (save-excursion (let* ((env (car texmathp-why)) (pos (cdr texmathp-why)) (delims TeX-make-inline-delims)) (cond ((member env '("\\(" "$"))) ((member env '("\\[" "$$")) (goto-char pos) (delete-char 2) (let ((start (point)) (end-delim (if (equal env "\\[") "\\]" "$$"))) (search-forward end-delim) (delete-char -2) (TeX-make-inline--finalize-region start (point) delims))) (t (goto-char pos) (kill-line) (let ((start (point))) (search-forward (concat "\\end{" env "}")) (beginning-of-line) (kill-line) (TeX-make-inline--finalize-region start (point) delims)))))))) (defun TeX-make-inline--finalize-region (start end delims) "Finalize the inline conversion from START to END using DELIMS." (save-restriction (narrow-to-region start end) (whitespace-cleanup) (goto-char (point-min)) (let ((re (concat "\\(?:" (mapconcat #'identity (if (boundp 'reftex-label-regexps) reftex-label-regexps '("\\\\label{[^}]*")) "\\|") "\\)"))) (while (re-search-forward re nil t) (replace-match ""))) (goto-char (point-min)) (while (looking-at "\\s-*$") (delete-line)) (beginning-of-line-text) (delete-region (point-min) (point)) (goto-char (point-max)) (while (and (> (point) (point-min)) (progn (forward-line -1) (looking-at "\\s-*$"))) (delete-line)) (end-of-line) (skip-chars-backward " \t") (delete-region (point) (point-max)) (goto-char (point-min)) (insert (car delims)) (goto-char (point-max)) (insert "\n") (backward-char) (while (looking-back "[.,;:!?]" 5) (backward-char)) (insert (cdr delims)) (while (> (count-lines (point-min) (point-max)) 1) (join-line)))) --8<---------------cut here---------------end--------------->8--- I haven't prepared this as a patch because I'm not sure where to put it or where to document it. I looked around, and couldn't find a natural place. If no better idea comes to mind, then perhaps some new "miscellaneous commands" section of latex.el, with a corresponding section in the manual? For what it's worth, there are a couple of other editing-related commands I'd be inclined to propose. Any feedback welcome. Thanks, best, Paul From unknown Sat Jun 14 19:44:59 2025 X-Loop: help-debbugs@gnu.org Subject: bug#78586: TeX-make-inline Resent-From: Arash Esbati Original-Sender: "Debbugs-submit" Resent-CC: bug-auctex@gnu.org Resent-Date: Tue, 27 May 2025 12:59:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 78586 X-GNU-PR-Package: auctex X-GNU-PR-Keywords: To: "Paul D. Nelson" Cc: 78586@debbugs.gnu.org Received: via spool by 78586-submit@debbugs.gnu.org id=B78586.174835069320037 (code B ref 78586); Tue, 27 May 2025 12:59:02 +0000 Received: (at 78586) by debbugs.gnu.org; 27 May 2025 12:58:13 +0000 Received: from localhost ([127.0.0.1]:40053 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1uJtsj-0005D6-Cd for submit@debbugs.gnu.org; Tue, 27 May 2025 08:58:13 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:44954) by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.84_2) (envelope-from ) id 1uJtse-0005Cg-6H for 78586@debbugs.gnu.org; Tue, 27 May 2025 08:58:10 -0400 Received: from fencepost.gnu.org ([2001:470:142:3::e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uJtsX-00040m-Ge; Tue, 27 May 2025 08:58:01 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org; s=fencepost-gnu-org; h=MIME-Version:Date:References:In-Reply-To:Subject:To: From; bh=00WOnd+iQz27WMuNH6cwi24SuO1dFQMVPvrCU5M/Q00=; b=LwE69OzLzbs7Z+ouG0Tt B2qxelra/fZodt7GyUbIQCPlblLRDEFX6cL2LmMN9pY0mJxP81+CJzAKdDTgLjTL8ji3jSC9HoWcn nvSipMb53BGfHDfxAMri15LBAVZDm6mfyz7SJEwp/rhxyQhB+saBmn5mk2cwnMOir5XrrGG1VlR79 h4eV7WuzxE2hHCbC5WujHSCgc8ZIJI7LGK8EtzI7IzrG1N7HkRMTbWFgror+t9TG3ljhiQnLxavhG WqEo6Hxm06Gxz9QbvNRZtktoMXcKpPPPWndq/Scllqx0HPnv4O+p7bfSYGFaV+evfTh+JInV//bgm CVYZSvnpELPruw==; From: Arash Esbati In-Reply-To: References: Date: Tue, 27 May 2025 14:57:56 +0200 Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable X-Spam-Score: -2.3 (--) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) Hi Paul, "Paul D. Nelson" writes: > We had discussed in an earlier thread (bug#78006) the possibility of > adding some of my editing commands to AUCTeX (as standalone commands, > without default binds). Thanks for sharing. I have some comments below: > We could start with this one, discussed a bit in that thread: > > (defcustom TeX-make-inline-delims '("$" . "$") > "Delimiters for `TeX-make-inline' to surround inline LaTeX math." > :type '(radio (const :tag "Dollar ($...$)" ("$" . "$")) > (const :tag "Paren (\\(...\\))" ("\\(" . "\\)")) > (cons :tag "Custom delimiters" > (string :tag "Left") (string :tag "Right")))) Do we really need this? Can we just take the value of `TeX-electric-math', and make an assumption if it's nil? > (defun TeX-make-inline () This function is LaTeX centric, right? So I would call is `LaTeX-make-inline-math' or something and put it in latex.el. > "Convert LaTeX display math environment at point to inline math. > Removes the enclosing math environment (such as \\[...\\] or > \\begin{equation}...\\end{equation}). Replaces it with inline math > surrounded by `TeX-make-inline-delims', surrounded by `TeX-electric-math' if non-nil, or \"$..$\", > fitting the result onto one > line. Leaves any trailing punctuation outside the math delimiters." > (interactive) > (when (texmathp) > (when (fboundp 'preview-clearout-at-point) > (preview-clearout-at-point)) > (save-excursion > (let* ((env (car texmathp-why)) > (pos (cdr texmathp-why)) > (delims TeX-make-inline-delims)) (delims (or TeX-electric-math '("$" . "$"))) > (cond > ((member env '("\\(" "$"))) > ((member env '("\\[" "$$")) > (goto-char pos) > (delete-char 2) > (let ((start (point)) > (end-delim (if (equal env "\\[") "\\]" "$$"))) > (search-forward end-delim) > (delete-char -2) > (TeX-make-inline--finalize-region start (point) delims))) > (t > (goto-char pos) > (kill-line) > (let ((start (point))) > (search-forward (concat "\\end{" env "}")) > (beginning-of-line) > (kill-line) > (TeX-make-inline--finalize-region start (point) delims)))))))) > > (defun TeX-make-inline--finalize-region (start end delims) (defun LaTeX--whatever-we-agree-to (...) Would it be possible to write an ERT-test for feature? > I haven't prepared this as a patch because I'm not sure where to put it > or where to document it. I looked around, and couldn't find a natural > place. I will have a look, will try to make a suggestion. > For what it's worth, there are a couple of other editing-related > commands I'd be inclined to propose. =F0=9F=91=8D Best, Arash From unknown Sat Jun 14 19:44:59 2025 X-Loop: help-debbugs@gnu.org Subject: bug#78586: TeX-make-inline References: Resent-From: "Paul D. Nelson" Original-Sender: "Debbugs-submit" Resent-CC: bug-auctex@gnu.org Resent-Date: Tue, 27 May 2025 15:00:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 78586 X-GNU-PR-Package: auctex X-GNU-PR-Keywords: To: Arash Esbati Cc: 78586@debbugs.gnu.org Received: via spool by 78586-submit@debbugs.gnu.org id=B78586.174835795023138 (code B ref 78586); Tue, 27 May 2025 15:00:02 +0000 Received: (at 78586) by debbugs.gnu.org; 27 May 2025 14:59:10 +0000 Received: from localhost ([127.0.0.1]:42375 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1uJvll-000611-5u for submit@debbugs.gnu.org; Tue, 27 May 2025 10:59:09 -0400 Received: from mail-ej1-x635.google.com ([2a00:1450:4864:20::635]:52559) by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.84_2) (envelope-from ) id 1uJvli-0005zy-H1 for 78586@debbugs.gnu.org; Tue, 27 May 2025 10:59:07 -0400 Received: by mail-ej1-x635.google.com with SMTP id a640c23a62f3a-acb5ec407b1so584233366b.1 for <78586@debbugs.gnu.org>; Tue, 27 May 2025 07:59:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1748357940; x=1748962740; darn=debbugs.gnu.org; h=mime-version:message-id:date:in-reply-to:subject:cc:to:from:from:to :cc:subject:date:message-id:reply-to; bh=laT1D2N0/TIuBa3+5TnTL9LtM/CswcDt4OdFvkTXlD4=; b=AkVXMEJteOBk34zqgnqLFBDIwm3BTA4xszb5uAbWlt7cfhpmXFMQMpH3H5vo726hRv DetIj13DaURRY18xhsNsnVP8vJchjwaeS/hJmMDTSBhKyMMqQoA+cpMIMhJKKlO9JUjn KbwCmUvz8Bxq97cI/S9Svgg6d64iI3EXAczTNKLilLRLi4UKufNhH8pko/gDgT5ElKR9 8cJ2b0525DD5Z2sye5UAAMb287j4mH314MuGnl+aOkZemKjrPHaxp2Dm4HrzjrDOBrqL s8+0MkDQWHr5fMC5wgUn0YiuYd/PwaADqRhCstwjCUqYsKJSAUTIuNceDUEh8D+C83Cw ikFg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1748357940; x=1748962740; h=mime-version:message-id:date:in-reply-to:subject:cc:to:from :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=laT1D2N0/TIuBa3+5TnTL9LtM/CswcDt4OdFvkTXlD4=; b=Fou2K2ixmgJLiVWCxCbxxi/LraApe8f1nguFQ95uHurywVWHG2aIfvaGyvJHQ7eute hpF35UiMy/wQj0HqPMIwkhMWDFk9WPyWLXp9MMydRiG1mGXrPnyM14OX2rrlyILFEXJP +M43XOhz6qd7qEZ1nnwo4NNxg9hy0uMS0zCY3ayoEAZ8dMy5dM27ermXkPdkQmlrZ74w CvhfSIvGzeYhzuJNZoZyZE09FvE0WiomZwH/lj/Bx3kWVMkDe6GkyOfHq5rd1TgYJn+X yfBU2sp+UynXQgcToqTT7LM084bT3X6+tChF3gvkH6iMOmPJDA29RjKW8TALFkt3u3cj tF5Q== X-Gm-Message-State: AOJu0YxGp2AUzr/RjkHIEThdNETchMUld+U3RPqpcVmygeXJ53EkXa9P OOgpMQPXphHYPSlSwQjxTLCBzJgrIX/BeUXQxvzfM7bnvwiq0APRIeXb20sPeJ3lhFo= X-Gm-Gg: ASbGnctJomHG88/Ws2c4VzT1E80iDllk5YUAq1Lc/eyrwBkZMuJVVIzhh3pJGgBHrZ1 OeB9qYzgAfbuxmzixo9fhYQjwTG3+/ruwXW8HxwM+grbtHpby5BGvc+lJemsVx3/1F5Qr1jHDja IgNKt3UAlXK/+AZvNI+i/7ocpf+w3ET0dAbqi2HoY3QtAMPx9v8mGYlzLNaOAyECkkWXz6feFAq fUZHN3HnwfnoGhEg2QQD64UOf2gbaGLzqoluFRty/TioBtz37EEAv8gPiVgg48pBcLMMOK5EOwR WyrrVn4X1wjjxr8wSgi2eVth9UVh+hd1wvVuCtcYim8ddzQlo692ilPMjijpYoAhDAW8PQ+KX02 WLO9uV4cn4qDx X-Google-Smtp-Source: AGHT+IFc+YXPAjz3BHdSV+QA9Fy91SyUb7rjJoLZG9FEbG4KNYmH8Ay0d7DYBp+D57AaCmNp4pc1Qg== X-Received: by 2002:a17:907:72cf:b0:ad2:417b:2ab5 with SMTP id a640c23a62f3a-ad85b32d8e0mr938657666b.60.1748357940026; Tue, 27 May 2025 07:59:00 -0700 (PDT) Received: from localhost (users-1190.st.net.au.dk. [130.225.0.251]) by smtp.gmail.com with UTF8SMTPSA id a640c23a62f3a-ad52d498737sm1857367666b.138.2025.05.27.07.58.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 27 May 2025 07:58:59 -0700 (PDT) From: "Paul D. Nelson" In-Reply-To: (message from Arash Esbati on Tue, 27 May 2025 14:57:56 +0200) Date: Tue, 27 May 2025 16:58:58 +0200 Message-ID: MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Spam-Score: 0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain Hi Arash, thanks for your feedback. I put the updated draft at the end of this message (to be converted into a patch once one of us thinks of a good place to put it), and attach some tests. Paul --=-=-= Content-Type: application/emacs-lisp Content-Disposition: attachment; filename=latex-make-inline-test.el Content-Transfer-Encoding: quoted-printable ;;; latex-make-inline-test.el --- tests for LaTeX-make-inline -*- lexical-= binding: t; -*- ;; Copyright (C) 2025 Free Software Foundation, Inc. ;; This file is part of AUCTeX. ;; AUCTeX is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) ;; any later version. ;; AUCTeX is distributed in the hope that it will be useful, but ;; WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;; General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with AUCTeX; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA ;; 02110-1301, USA. ;;; Code: (require 'ert) (require 'cl-lib) (require 'latex) (defmacro latex-make-inline-test--with-temp-buffer (contents &rest body) (declare (indent 1) (debug t)) `(with-temp-buffer (LaTeX-mode) (insert ,contents) (goto-char (point-min)) (cl-letf (((symbol-function 'preview-clearout-at-point) #'ignore)) ,@body))) (ert-deftest LaTeX-make-inline-bracket-period () "Convert \\[..\\] to $..$ and keep trailing period." (latex-make-inline-test--with-temp-buffer "We have\n\\[ a+b =3D c. \\]" (search-forward "b") (LaTeX-make-inline) (should (equal (buffer-string) "We have $a+b =3D c$.")))) (ert-deftest LaTeX-make-inline-double-dollar () "Convert $$..$$ to $..$." (latex-make-inline-test--with-temp-buffer "$$x!$$" (search-forward "x") (LaTeX-make-inline) (should (equal (buffer-string) "$x$!")))) (ert-deftest LaTeX-make-inline-electric-math () "Respect `TeX-electric-math'." (let ((TeX-electric-math '("\\(" . "\\)"))) (latex-make-inline-test--with-temp-buffer "\\[ x \\]" (search-forward "x") (LaTeX-make-inline) (should (equal (buffer-string) "\\(x\\)"))))) (ert-deftest LaTeX-make-inline-equation-env () "Convert equation environment, drop \\label, keep comma." (latex-make-inline-test--with-temp-buffer "\\begin{equation}\n\\label{l}x+y,\n\\end{equation}\n" (search-forward "x") (let ((TeX-electric-math '("\\(" . "\\)"))) (LaTeX-make-inline) (should (equal (buffer-string) "\\(x+y\\),\n"))))) (ert-deftest LaTeX-make-inline-noop () "Call inside inline math leaves buffer unchanged." (latex-make-inline-test--with-temp-buffer "Already $z$ inline." (search-forward "z") (LaTeX-make-inline) (should (equal (buffer-string) "Already $z$ inline.")))) ;;; latex-make-inline-test.el ends here --=-=-= Content-Type: text/plain --8<---------------cut here---------------start------------->8--- (defun LaTeX-make-inline () "Convert LaTeX display math environment at point to inline math. Removes the enclosing math environment (such as \\[...\\] or \\begin{equation}...\\end{equation}). Replaces it with inline math surrounded by surrounded by `TeX-electric-math' if non-nil, or \"$..$\", fitting the result onto one line. Leaves any trailing punctuation outside the math delimiters." (interactive) (when (texmathp) (when (fboundp 'preview-clearout-at-point) (preview-clearout-at-point)) (save-excursion (let* ((env (car texmathp-why)) (pos (cdr texmathp-why)) (delims (or TeX-electric-math '("$" . "$")))) (cond ((member env '("\\(" "$"))) ((member env '("\\[" "$$")) (goto-char pos) (when (looking-back "\n[[:space:]]*") (forward-char 2) (save-excursion (join-line)) (forward-char -2)) (delete-char 2) (let ((start (point)) (end-delim (if (equal env "\\[") "\\]" "$$"))) (search-forward end-delim) (delete-char -2) (if (looking-back "\n[[:space:]]*") (goto-char (match-beginning 0))) (LaTeX--make-inline-finalize-region start (point) delims))) (t (goto-char pos) (kill-whole-line) (let ((start (point))) (search-forward (concat "\\end{" env "}")) (beginning-of-line) (kill-whole-line) (backward-char) (LaTeX--make-inline-finalize-region start (point) delims)))))))) (defun LaTeX--make-inline-finalize-region (start end delims) "Finalize the inline conversion from START to END using DELIMS." (save-restriction (narrow-to-region start end) (goto-char (point-min)) (let ((re (concat "\\(?:" (mapconcat #'identity (if (boundp 'reftex-label-regexps) reftex-label-regexps '("\\\\label{[^}]*")) "\\|") "\\)"))) (while (re-search-forward re nil t) (replace-match ""))) (goto-char (point-min)) (while (looking-at "\\s-*$") (delete-line)) (beginning-of-line-text) (delete-region (point-min) (point)) (goto-char (point-max)) (while (and (> (point) (point-min)) (progn (forward-line -1) (looking-at "\\s-*$"))) (delete-line)) (end-of-line) (skip-chars-backward " \t") (delete-region (point) (point-max)) (goto-char (point-min)) (insert (car delims)) (goto-char (point-max)) (while (looking-back "[.,;:!?]" (max (point-min) (- (point) 5))) (backward-char)) (insert (cdr delims)) (while (> (count-lines (point-min) (point-max)) 1) (join-line))) (join-line)) --8<---------------cut here---------------end--------------->8--- --=-=-=-- From unknown Sat Jun 14 19:44:59 2025 X-Loop: help-debbugs@gnu.org Subject: bug#78586: TeX-make-inline Resent-From: Arash Esbati Original-Sender: "Debbugs-submit" Resent-CC: bug-auctex@gnu.org Resent-Date: Thu, 29 May 2025 07:27:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 78586 X-GNU-PR-Package: auctex X-GNU-PR-Keywords: To: "Paul D. Nelson" Cc: 78586@debbugs.gnu.org Received: via spool by 78586-submit@debbugs.gnu.org id=B78586.174850361517606 (code B ref 78586); Thu, 29 May 2025 07:27:02 +0000 Received: (at 78586) by debbugs.gnu.org; 29 May 2025 07:26:55 +0000 Received: from localhost ([127.0.0.1]:33282 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1uKXfC-0004Zt-Kb for submit@debbugs.gnu.org; Thu, 29 May 2025 03:26:55 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:59972) by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.84_2) (envelope-from ) id 1uKXfA-0004ZZ-MA for 78586@debbugs.gnu.org; Thu, 29 May 2025 03:26:53 -0400 Received: from fencepost.gnu.org ([2001:470:142:3::e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uKXf5-0005NR-9F; Thu, 29 May 2025 03:26:47 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org; s=fencepost-gnu-org; h=MIME-Version:Date:References:In-Reply-To:Subject:To: From; bh=0TfVnBxy6HawUxY8tM/sHGigYo4aIiPGBLy5TAjZaI4=; b=khZC0lwPQpRBVHtdB34j ra/IrLpn5im7sbaI39nRSLGky5q9hIchrRX2zIrKYiOrtRc/dtBNZUics1rhkrHXBDnPW6XPj6Vv2 x85CZtcC4p4wUZ4b65k51K1DDAMjiS7f30CnZUqTxC1pCN8TevEzC+Mu5lfB2mI1q1bmezM+zzQEg Hr0fotBCvYe3yv1klHEsSlZ0Cz+X7x+oWXvGYh2HEaAxCaceuNe4YRrmyIFhiCzk0fTPXhYfLY3Oi 4qNRJd4XvE6vjIcN2sMCLpRl+BoShc1ySfYvGixqKaK4Yn4KWVcdgAOPULQ8a8ndvIc7DrcjWo/le d2v+J5ynT57iiw==; From: Arash Esbati In-Reply-To: References: Date: Thu, 29 May 2025 09:26:42 +0200 Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: text/plain X-Spam-Score: -2.3 (--) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) Hi Paul, "Paul D. Nelson" writes: > Hi Arash, thanks for your feedback. You're welcome. > I put the updated draft at the end of this message (to be converted > into a patch once one of us thinks of a good place to put it), and > attach some tests. You said that you also have some other commands, right? So I suggest we put them at the end of latex.el, under ;; Utilities:. WDYT? Reg. manual: I suggest to document this command under @subheading Dollar Signs Maybe something like this: --8<---------------cut here---------------start------------->8--- diff --git a/doc/auctex.texi b/doc/auctex.texi index 0b486c8c..9602c062 100644 --- a/doc/auctex.texi +++ b/doc/auctex.texi @@ -484,6 +484,16 @@ to prevent unmatched dollar. Note that Texinfo mode does nothing special for @kbd{$}. It inserts dollar sign(s) just in the same way as the other normal keys do. +@AUCTeX{} provides the command @code{LaTeX-make-inline} which converts the +display math environment at point to inline math. + +@deffn Command LaTeX-make-inline +Convert @LaTeX{} display math environment at point to inline math. This +command replaces the enclosing math environment such as @samp{\[...\]} or +@samp{\begin@{equation@}...\end@{equation@}} with the value of +@code{TeX-electric-math} or @samp{$...$} by default. +@end deffn + @subheading Braces To avoid unbalanced braces, it is useful to insert them pairwise. You --8<---------------cut here---------------end--------------->8--- > (defun LaTeX-make-inline () > "Convert LaTeX display math environment at point to inline math. > Removes the enclosing math environment (such as \\[...\\] or > \\begin{equation}...\\end{equation}). Replaces it with inline math > surrounded by surrounded by `TeX-electric-math' if non-nil, or \"$..$\", > fitting the result onto one line. Leaves any trailing punctuation > outside the math delimiters." Please use active voice, maybe something like this: "Convert LaTeX display math environment at point to inline math. Remove the enclosing math environment (such as \\[...\\] or \\begin{equation}...\\end{equation}) and replace it with inline math surrounded by `TeX-electric-math' if non-nil, or \"$...$\", fitting the result onto one line. Finally, leave any trailing punctuation outside the math delimiters." > (interactive) > (when (texmathp) > (when (fboundp 'preview-clearout-at-point) > (preview-clearout-at-point)) > (save-excursion > (let* ((env (car texmathp-why)) > (pos (cdr texmathp-why)) > (delims (or TeX-electric-math '("$" . "$")))) Why `let*'? > (cond > ((member env '("\\(" "$"))) > ((member env '("\\[" "$$")) > (goto-char pos) > (when (looking-back "\n[[:space:]]*") > (forward-char 2) > (save-excursion (join-line)) > (forward-char -2)) > (delete-char 2) > (let ((start (point)) > (end-delim (if (equal env "\\[") "\\]" "$$"))) > (search-forward end-delim) > (delete-char -2) > (if (looking-back "\n[[:space:]]*") > (goto-char (match-beginning 0))) > (LaTeX--make-inline-finalize-region start (point) delims))) > (t > (goto-char pos) > (kill-whole-line) > (let ((start (point))) > (search-forward (concat "\\end{" env "}")) > (beginning-of-line) > (kill-whole-line) > (backward-char) > (LaTeX--make-inline-finalize-region start (point) delims)))))))) > > (defun LaTeX--make-inline-finalize-region (start end delims) > "Finalize the inline conversion from START to END using DELIMS." > (save-restriction > (narrow-to-region start end) > > (goto-char (point-min)) > (let ((re > (concat "\\(?:" > (mapconcat #'identity > (if (boundp 'reftex-label-regexps) > reftex-label-regexps > '("\\\\label{[^}]*")) > "\\|") > "\\)"))) This looks somewhat easier to me: (let ((re (concat "\\(?:" (if (bound-and-true-p reftex-label-regexps) (mapconcat #'identity reftex-label-regexps "\\|") "\\\\label{[^}]*}") "\\)"))) And note the missing '}' in "\\\\label{[^}]*". Otherwise LGTM. Best, Arash From unknown Sat Jun 14 19:44:59 2025 X-Loop: help-debbugs@gnu.org Subject: bug#78586: TeX-make-inline References: Resent-From: "Paul D. Nelson" Original-Sender: "Debbugs-submit" Resent-CC: bug-auctex@gnu.org Resent-Date: Thu, 29 May 2025 09:17:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 78586 X-GNU-PR-Package: auctex X-GNU-PR-Keywords: To: Arash Esbati Cc: 78586@debbugs.gnu.org Received: via spool by 78586-submit@debbugs.gnu.org id=B78586.174851017015213 (code B ref 78586); Thu, 29 May 2025 09:17:01 +0000 Received: (at 78586) by debbugs.gnu.org; 29 May 2025 09:16:10 +0000 Received: from localhost ([127.0.0.1]:33875 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1uKZMv-0003xE-0Y for submit@debbugs.gnu.org; Thu, 29 May 2025 05:16:09 -0400 Received: from mail-ed1-x531.google.com ([2a00:1450:4864:20::531]:54551) by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.84_2) (envelope-from ) id 1uKZMt-0003wG-1a for 78586@debbugs.gnu.org; Thu, 29 May 2025 05:16:07 -0400 Received: by mail-ed1-x531.google.com with SMTP id 4fb4d7f45d1cf-602039559d8so1286852a12.1 for <78586@debbugs.gnu.org>; Thu, 29 May 2025 02:16:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1748510161; x=1749114961; darn=debbugs.gnu.org; h=mime-version:message-id:date:in-reply-to:subject:cc:to:from:from:to :cc:subject:date:message-id:reply-to; bh=dS4NGkfxpk1z5ViNidzpzNstx8ZZwfpkwT1r2rFAqbM=; b=gBahwTtz8GnXweCz2tCb0ZKt99bgSkO+uknHvSpYAGLc/njmSKP42RJv9FpTncXOT4 gA3lubj4Bgj3pTGOQ+uKdS92JwYIfLYa33VtEonaKHG5QqgRiUIhs2WLgCSTgAffdISM y5wsrHq4K6zd/tRlBwcvdkF+J4A0ffxhCS2gfNcLiTdQz0UUHBpPh/KFrhlisiGjeuIX Po9+pf1A/6JbO541Q96KccJnlrynVwn8L60cQZOeYt3Zh5YKviUarT4lVTMEVTIKs/Xy a3vEZZq5j/FF00ABnPZekqcfbahkbwqGduShrvfJWuNXaU1PiBz2lN4j3Pjxw3Q5z9Ek 5JPg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1748510161; x=1749114961; h=mime-version:message-id:date:in-reply-to:subject:cc:to:from :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=dS4NGkfxpk1z5ViNidzpzNstx8ZZwfpkwT1r2rFAqbM=; b=kbZplo5clPd/aaEO/n+IagVTHKjXnrbdU/6Dz79HKlOiicGf/PUy/3aKSnea6v3NGf AZuFoZT9ulgySR0aOIHQA0gBzZKhOj/htKLMw/v5y9STv2am/njQGG1tlfsc9vuBJXGS Mon2fNcop50eh8o5KNAzxdT5JWAct0Av7jCXBPvRCKzToBKqBYM4VlEX6U2BXH46lQOu VBe3k7t6X8eAc52L7vKpS3kQwj4F94fO2R2S6ECRo2/1DTiYbKAz5T9u6GXDdJ2ePBsF dfY/TqPyc2Dr3aIi+c0LU1RnfYfkCj1U5ccgWs4QL6wLB/QeyUeTqCLDWeY7awPWknnx HkbA== X-Gm-Message-State: AOJu0YxbtpEWHDtoOH8mLRvVS+fZk0+yCX41FZgrMnbcAbwnb47ASlul OmXDkdij2zgxmgJI8SnOPFNi/EEEVj/+nK9yIbbrZ8eXoloXGhAm7E+gJRU9hjdu X-Gm-Gg: ASbGnct5KFObOXyE3QV6zhXuDMhoSG3426pe4m2Yph6zg1WMNJIllqWc2vlCmlBPyga hCnCM3F/6OadC3NUAwbULEeVWqaB2QayIEluK8uXCrpKMa1xgyk3Cjv4iT8bzGZAsWc6C7UO2+u 9XkdeBMjVMJAK5djtAauFLxLgH709Tp48mTvFUe1eliM/gHgE0MENMnBXSgCJpKE5+wrpD8uDSd 2j7FOzpk1oP63TuRrzBIFsmkPY3V0H2cS9PcTjqTafk1k52wSOugKAbbShBsV2Wm8a4K9Sqy21s ZPjvKn19BTKwwQL/KW6CoGiO82RjG5uedSyqeAuqXckhcAes3qFiYzJ4SBudtW8z43o= X-Google-Smtp-Source: AGHT+IG+gWS1Qh7+4vWISm+VMnw17DLaMXsqPGLCz5k58cBHKHlDIJJJ18OovwOjkkPImfBNjc/+aw== X-Received: by 2002:a17:907:553:b0:ad8:9041:7706 with SMTP id a640c23a62f3a-ad890417d9fmr615748466b.56.1748510160365; Thu, 29 May 2025 02:16:00 -0700 (PDT) Received: from localhost ([185.229.154.43]) by smtp.gmail.com with UTF8SMTPSA id a640c23a62f3a-ada5d7fed53sm106864166b.27.2025.05.29.02.15.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 29 May 2025 02:15:59 -0700 (PDT) From: "Paul D. Nelson" In-Reply-To: (message from Arash Esbati on Thu, 29 May 2025 09:26:42 +0200) Date: Thu, 29 May 2025 11:15:58 +0200 Message-ID: MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Spam-Score: 0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain Hi Arash, Thanks again for your feedback, and sounds good on all counts. Please see attached. Thanks, best, Paul --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-Add-LaTeX-make-inline-command.patch >From 129d469a2ab47f61b10f5eb9557de7e525a3830f Mon Sep 17 00:00:00 2001 From: Paul Nelson Date: Thu, 29 May 2025 11:14:11 +0200 Subject: [PATCH] Add LaTeX-make-inline command * latex.el (LaTeX-make-inline): New command. (LaTeX--make-inline-finalize-region): New helper function. * tests/latex/latex-make-inline-test.el: New test file. (latex-make-inline-test--with-temp-buffer): New test macro. (LaTeX-make-inline-bracket-period) (LaTeX-make-inline-double-dollar) (LaTeX-make-inline-electric-math, LaTeX-make-inline-equation-env) (LaTeX-make-inline-noop): New test cases. * doc/auctex.texi (Quotes): Document LaTeX-make-inline. --- doc/auctex.texi | 10 ++++ latex.el | 82 +++++++++++++++++++++++++++ tests/latex/latex-make-inline-test.el | 79 ++++++++++++++++++++++++++ 3 files changed, 171 insertions(+) create mode 100644 tests/latex/latex-make-inline-test.el diff --git a/doc/auctex.texi b/doc/auctex.texi index 0b486c8c..9602c062 100644 --- a/doc/auctex.texi +++ b/doc/auctex.texi @@ -484,6 +484,16 @@ to prevent unmatched dollar. Note that Texinfo mode does nothing special for @kbd{$}. It inserts dollar sign(s) just in the same way as the other normal keys do. +@AUCTeX{} provides the command @code{LaTeX-make-inline} which converts the +display math environment at point to inline math. + +@deffn Command LaTeX-make-inline +Convert @LaTeX{} display math environment at point to inline math. This +command replaces the enclosing math environment such as @samp{\[...\]} or +@samp{\begin@{equation@}...\end@{equation@}} with the value of +@code{TeX-electric-math} or @samp{$...$} by default. +@end deffn + @subheading Braces To avoid unbalanced braces, it is useful to insert them pairwise. You diff --git a/latex.el b/latex.el index 797513f2..6e34dfc5 100644 --- a/latex.el +++ b/latex.el @@ -9551,6 +9551,88 @@ no caption key is found, an error is issued. See also the docstring of "LARGE" "huge" "Huge") "List of LaTeX font size declarations.") +(defun LaTeX-make-inline () + "Convert LaTeX display math environment at point to inline math. +Remove the enclosing math environment (such as \\[...\\] or +\\begin{equation}...\\end{equation}) and replace it with inline math +surrounded by `TeX-electric-math' if non-nil, or \"$..$\", fitting the +result onto one line. Finally, leave any trailing punctuation outside +the math delimiters." + (interactive) + (when (texmathp) + (when (fboundp 'preview-clearout-at-point) + (preview-clearout-at-point)) + (save-excursion + (let ((env (car texmathp-why)) + (pos (cdr texmathp-why)) + (delims (or TeX-electric-math '("$" . "$")))) + (cond + ((member env '("\\(" "$"))) + ((member env '("\\[" "$$")) + (goto-char pos) + (when (looking-back "\n[[:space:]]*") + (forward-char 2) + (save-excursion (join-line)) + (forward-char -2)) + (delete-char 2) + (let ((start (point)) + (end-delim (if (equal env "\\[") "\\]" "$$"))) + (search-forward end-delim) + (delete-char -2) + (if (looking-back "\n[[:space:]]*") + (goto-char (match-beginning 0))) + (LaTeX--make-inline-finalize-region start (point) delims))) + (t + (goto-char pos) + (kill-whole-line) + (let ((start (point))) + (search-forward (concat "\\end{" env "}")) + (beginning-of-line) + (kill-whole-line) + (backward-char) + (LaTeX--make-inline-finalize-region start (point) delims)))))))) + +(defun LaTeX--make-inline-finalize-region (start end delims) + "Finalize the inline conversion from START to END using DELIMS." + (save-restriction + (narrow-to-region start end) + + (goto-char (point-min)) + (let ((re (concat "\\(?:" + (if (bound-and-true-p reftex-label-regexps) + (mapconcat #'identity reftex-label-regexps "\\|") + "\\\\label{[^}]*}") + "\\)"))) + (while (re-search-forward re nil t) + (replace-match ""))) + + (goto-char (point-min)) + (while (looking-at "\\s-*$") + (delete-line)) + (beginning-of-line-text) + (delete-region (point-min) (point)) + + (goto-char (point-max)) + (while (and (> (point) (point-min)) + (progn (forward-line -1) + (looking-at "\\s-*$"))) + (delete-line)) + (end-of-line) + (skip-chars-backward " \t") + (delete-region (point) (point-max)) + + (goto-char (point-min)) + (insert (car delims)) + (goto-char (point-max)) + + (while (looking-back "[.,;:!?]" (max (point-min) (- (point) 5))) + (backward-char)) + (insert (cdr delims)) + + (while (> (count-lines (point-min) (point-max)) 1) + (join-line))) + (join-line)) + (provide 'latex) ;;; latex.el ends here diff --git a/tests/latex/latex-make-inline-test.el b/tests/latex/latex-make-inline-test.el new file mode 100644 index 00000000..f4dbadf0 --- /dev/null +++ b/tests/latex/latex-make-inline-test.el @@ -0,0 +1,79 @@ +;;; latex-make-inline-test.el --- tests for LaTeX-make-inline -*- lexical-binding: t; -*- + +;; Copyright (C) 2025 Free Software Foundation, Inc. + +;; This file is part of AUCTeX. + +;; AUCTeX is free software; you can redistribute it and/or modify it +;; under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. + +;; AUCTeX is distributed in the hope that it will be useful, but +;; WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with AUCTeX; see the file COPYING. If not, write to the Free +;; Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +;; 02110-1301, USA. + +;;; Code: + +(require 'ert) +(require 'cl-lib) +(require 'latex) + +(defmacro latex-make-inline-test--with-temp-buffer (contents &rest body) + (declare (indent 1) (debug t)) + `(with-temp-buffer + (LaTeX-mode) + (insert ,contents) + (goto-char (point-min)) + (cl-letf (((symbol-function 'preview-clearout-at-point) #'ignore)) + ,@body))) + +(ert-deftest LaTeX-make-inline-bracket-period () + "Convert \\[..\\] to $..$ and keep trailing period." + (latex-make-inline-test--with-temp-buffer + "We have\n\\[ a+b = c. \\]" + (search-forward "b") + (LaTeX-make-inline) + (should (equal (buffer-string) "We have $a+b = c$.")))) + +(ert-deftest LaTeX-make-inline-double-dollar () + "Convert $$..$$ to $..$." + (latex-make-inline-test--with-temp-buffer + "$$x!$$" + (search-forward "x") + (LaTeX-make-inline) + (should (equal (buffer-string) "$x$!")))) + +(ert-deftest LaTeX-make-inline-electric-math () + "Respect `TeX-electric-math'." + (let ((TeX-electric-math '("\\(" . "\\)"))) + (latex-make-inline-test--with-temp-buffer + "\\[ x \\]" + (search-forward "x") + (LaTeX-make-inline) + (should (equal (buffer-string) "\\(x\\)"))))) + +(ert-deftest LaTeX-make-inline-equation-env () + "Convert equation environment, drop \\label, keep comma." + (latex-make-inline-test--with-temp-buffer + "\\begin{equation}\n\\label{l}x+y,\n\\end{equation}\n" + (search-forward "x") + (let ((TeX-electric-math '("\\(" . "\\)"))) + (LaTeX-make-inline) + (should (equal (buffer-string) "\\(x+y\\),\n"))))) + +(ert-deftest LaTeX-make-inline-noop () + "Call inside inline math leaves buffer unchanged." + (latex-make-inline-test--with-temp-buffer + "Already $z$ inline." + (search-forward "z") + (LaTeX-make-inline) + (should (equal (buffer-string) "Already $z$ inline.")))) + +;;; latex-make-inline-test.el ends here -- 2.39.3 (Apple Git-145) --=-=-=-- From unknown Sat Jun 14 19:44:59 2025 X-Loop: help-debbugs@gnu.org Subject: bug#78586: TeX-make-inline Resent-From: Ikumi Keita Original-Sender: "Debbugs-submit" Resent-CC: bug-auctex@gnu.org Resent-Date: Thu, 29 May 2025 18:36:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 78586 X-GNU-PR-Package: auctex X-GNU-PR-Keywords: To: "Paul D. Nelson" Cc: Arash Esbati , 78586@debbugs.gnu.org Received: via spool by 78586-submit@debbugs.gnu.org id=B78586.174854371414597 (code B ref 78586); Thu, 29 May 2025 18:36:02 +0000 Received: (at 78586) by debbugs.gnu.org; 29 May 2025 18:35:14 +0000 Received: from localhost ([127.0.0.1]:38864 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1uKi5x-0003nM-TD for submit@debbugs.gnu.org; Thu, 29 May 2025 14:35:14 -0400 Received: from smtp1a.inetd.co.jp ([210.129.88.11]:45952) by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.84_2) (envelope-from ) id 1uKi5t-0003ij-3G for 78586@debbugs.gnu.org; Thu, 29 May 2025 14:35:11 -0400 Received: from localhost (42-144-37-89.rev.home.ne.jp [42.144.37.89]) by smtp1a.inetd.co.jp (Postfix) with ESMTPSA id C151877; Fri, 30 May 2025 03:35:05 +0900 (JST) From: Ikumi Keita In-reply-to: References: Comments: In-reply-to "Paul D. Nelson" message dated "Thu, 29 May 2025 11:15:58 +0200." X-Mailer: MH-E 8.6+git; nmh 1.8; Emacs 30.1 MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Date: Fri, 30 May 2025 03:35:05 +0900 Message-ID: <9450.1748543705@localhost> X-Spam-Score: 0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Hi Paul, >>>>> "Paul D. Nelson" writes: > Thanks again for your feedback, and sounds good on all counts. Please > see attached. Thanks for your continuous contributions. I have a very minor comment this time. > +(defun LaTeX-make-inline () > + "Convert LaTeX display math environment at point to inline math. > +Remove the enclosing math environment (such as \\[...\\] or ^^^ In docstrings, we need \=3D to escape \[ which introduces command-to-keybind syntax =F0=9F=99=83 Bye, Ikumi Keita #StandWithUkraine #StopWarInUkraine #Gaza #StopMassiveKilling #CeasefireNOW From unknown Sat Jun 14 19:44:59 2025 X-Loop: help-debbugs@gnu.org Subject: bug#78586: TeX-make-inline References: Resent-From: "Paul D. Nelson" Original-Sender: "Debbugs-submit" Resent-CC: bug-auctex@gnu.org Resent-Date: Thu, 29 May 2025 18:49:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 78586 X-GNU-PR-Package: auctex X-GNU-PR-Keywords: To: Ikumi Keita Cc: arash@gnu.org, 78586@debbugs.gnu.org Received: via spool by 78586-submit@debbugs.gnu.org id=B78586.174854448718102 (code B ref 78586); Thu, 29 May 2025 18:49:01 +0000 Received: (at 78586) by debbugs.gnu.org; 29 May 2025 18:48:07 +0000 Received: from localhost ([127.0.0.1]:38957 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1uKiIQ-0004ht-Vx for submit@debbugs.gnu.org; Thu, 29 May 2025 14:48:07 -0400 Received: from mail-ed1-x530.google.com ([2a00:1450:4864:20::530]:59797) by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.84_2) (envelope-from ) id 1uKiIN-0004hL-Gk for 78586@debbugs.gnu.org; Thu, 29 May 2025 14:48:04 -0400 Received: by mail-ed1-x530.google.com with SMTP id 4fb4d7f45d1cf-604533a2f62so2263127a12.3 for <78586@debbugs.gnu.org>; Thu, 29 May 2025 11:48:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1748544477; x=1749149277; darn=debbugs.gnu.org; h=mime-version:message-id:date:in-reply-to:subject:cc:to:from:from:to :cc:subject:date:message-id:reply-to; bh=7av0hB5a+uv6imAvR6zdqQudE/tMpenNGKax7EdPH7g=; b=h5oBXs7eZg9xJXhVSXrmJpCxLrGAgTZ4+h4NmK2P2ihVO9MuBBfiHZx6KDjR/tC1su hi3Eu84nUZ4fVXuPyLXQHdaXFf8rY12wzfp6ueF9uz9Ku+vWRI3ZitydidwtsYBCzRWs C3b7I4t0CGKYnVRobDI47h/lE5GnZDVfilJIONidsliNA0EqFRi21zJMTLvaLpdz0600 p41YPNbOI08rhfGKz//Tlo5UVidhLK/F/JVLylzOeWGPovIzhfDgXKeWqes4rGDU4bgy 30RcK5xLwZQbhl5ivMQWgyruCtnI9fb9zFcv343XYeKYvDEIP8r1udJu4uDuHHpmY8VL tP0A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1748544477; x=1749149277; h=mime-version:message-id:date:in-reply-to:subject:cc:to:from :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=7av0hB5a+uv6imAvR6zdqQudE/tMpenNGKax7EdPH7g=; b=v6vaIP3YtYvjg598mJ7FdqwxunE2qjSsJPpDZNlrH8/b/cskYoy9QGkM4D40NSASdi Qv3KnuraOZN2EI56NKw+AK+5pGL1AXhyf7HWyw4PGMwPfd7UgjWeSlyrjIg3C8+qx4Lf ccLaKnwRNEngOvo7ik7PRSk3fzICC+c5grU9z1keE+cvvogzzF9At8FUC1nUtIV5sbZC Tk1voL+sUhG37jiU8r7+GXQUBFUM8WPtHNIZ03mwAacNeTHPkDekjZQukg5A6yg/cmne ttNjG0SyPuNoFoKSbVeiH3SYu/7okS9rZU5WgdWBg1r5AHz2kAqi9X2Qitf5YlA4btTw Yv1Q== X-Forwarded-Encrypted: i=1; AJvYcCVLOH3wOayHPeCOW1DYIH5t42AaFcKPO5Kr8h+bFagWddP4T5urdGZM1gVRRQfA+fasETV6nw==@debbugs.gnu.org X-Gm-Message-State: AOJu0YzJssEFL0sPscs2sZQ0AXOL4PPApx3muMfU1q7BnCVqCWu4sqb4 M9ob4h6CpZqNpFEyMbbnvtoPGykgyYNird2r6VQGR728URv2nsSVcmsW X-Gm-Gg: ASbGncsC2Yn9YhTnCNY3k6AzaWvHXyZnyDaatkRT2xbaGP80UcZXtAhJtHEFEU2go/D ktT7G8tmaO26EG3NhmhkZNMb+kHd5jgLMKMqpRHkIHgpD5r0MCj8GZlSHA9Ldp8/cx7FSOl62tf vVh/Hd7ysNF1arMgPcuaZ7jKDfh7Afe+pXbLOc2r+jPCkXAg8VXQuJuX8UVRYtRhnHevAcTDwhj 4sV1iSmO0hqJ6mKb1Ia/2pOgxF5ekRS6s7imZN9dPu/Pkqlb3RRk4rK958HiTiaPkyISBlriUnQ /62MwaT6F2C0BoRxGQeX2jywt04QzrJg2OE5ZigvOnRmXLkREjJ5gPuiLA== X-Google-Smtp-Source: AGHT+IEyKUJd7VQcNK8YcFt771cphWPbPx06BXd6Ton3R6I6mqyyaGOenzz5HKOKzHDPHdCp6PCiqg== X-Received: by 2002:a17:906:6a06:b0:ace:c518:1327 with SMTP id a640c23a62f3a-adb322d8a67mr58789466b.14.1748544476957; Thu, 29 May 2025 11:47:56 -0700 (PDT) Received: from localhost ([185.229.154.228]) by smtp.gmail.com with UTF8SMTPSA id a640c23a62f3a-ada6ad696d1sm186302066b.161.2025.05.29.11.47.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 29 May 2025 11:47:56 -0700 (PDT) From: "Paul D. Nelson" In-Reply-To: <9450.1748543705@localhost> (message from Ikumi Keita on Fri, 30 May 2025 03:35:05 +0900) Date: Thu, 29 May 2025 20:47:55 +0200 Message-ID: MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Spam-Score: 0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain Thanks Ikuya, good catch! Please find attached the updated patch. Paul --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-Add-LaTeX-make-inline-command.patch >From c5c70ca6e9b0f6e48429476792da877cd605a920 Mon Sep 17 00:00:00 2001 From: Paul Nelson Date: Thu, 29 May 2025 11:14:11 +0200 Subject: [PATCH] Add LaTeX-make-inline command * latex.el (LaTeX-make-inline): New command. (LaTeX--make-inline-finalize-region): New helper function. * tests/latex/latex-make-inline-test.el: New test file. (latex-make-inline-test--with-temp-buffer): New test macro. (LaTeX-make-inline-bracket-period) (LaTeX-make-inline-double-dollar) (LaTeX-make-inline-electric-math, LaTeX-make-inline-equation-env) (LaTeX-make-inline-noop): New test cases. * doc/auctex.texi (Quotes): Document LaTeX-make-inline. --- doc/auctex.texi | 10 ++++ latex.el | 82 +++++++++++++++++++++++++++ tests/latex/latex-make-inline-test.el | 79 ++++++++++++++++++++++++++ 3 files changed, 171 insertions(+) create mode 100644 tests/latex/latex-make-inline-test.el diff --git a/doc/auctex.texi b/doc/auctex.texi index 0b486c8c..9602c062 100644 --- a/doc/auctex.texi +++ b/doc/auctex.texi @@ -484,6 +484,16 @@ to prevent unmatched dollar. Note that Texinfo mode does nothing special for @kbd{$}. It inserts dollar sign(s) just in the same way as the other normal keys do. +@AUCTeX{} provides the command @code{LaTeX-make-inline} which converts the +display math environment at point to inline math. + +@deffn Command LaTeX-make-inline +Convert @LaTeX{} display math environment at point to inline math. This +command replaces the enclosing math environment such as @samp{\[...\]} or +@samp{\begin@{equation@}...\end@{equation@}} with the value of +@code{TeX-electric-math} or @samp{$...$} by default. +@end deffn + @subheading Braces To avoid unbalanced braces, it is useful to insert them pairwise. You diff --git a/latex.el b/latex.el index 797513f2..c305fa3a 100644 --- a/latex.el +++ b/latex.el @@ -9551,6 +9551,88 @@ no caption key is found, an error is issued. See also the docstring of "LARGE" "huge" "Huge") "List of LaTeX font size declarations.") +(defun LaTeX-make-inline () + "Convert LaTeX display math environment at point to inline math. +Remove the enclosing math environment (such as \\\\=[...\\\\=] or +\\begin{equation}...\\end{equation}) and replace it with inline math +surrounded by `TeX-electric-math' if non-nil, or \"$...$\", fitting the +result onto one line. Finally, leave any trailing punctuation outside +the math delimiters." + (interactive) + (when (texmathp) + (when (fboundp 'preview-clearout-at-point) + (preview-clearout-at-point)) + (save-excursion + (let ((env (car texmathp-why)) + (pos (cdr texmathp-why)) + (delims (or TeX-electric-math '("$" . "$")))) + (cond + ((member env '("\\(" "$"))) + ((member env '("\\[" "$$")) + (goto-char pos) + (when (looking-back "\n[[:space:]]*") + (forward-char 2) + (save-excursion (join-line)) + (forward-char -2)) + (delete-char 2) + (let ((start (point)) + (end-delim (if (equal env "\\[") "\\]" "$$"))) + (search-forward end-delim) + (delete-char -2) + (if (looking-back "\n[[:space:]]*") + (goto-char (match-beginning 0))) + (LaTeX--make-inline-finalize-region start (point) delims))) + (t + (goto-char pos) + (kill-whole-line) + (let ((start (point))) + (search-forward (concat "\\end{" env "}")) + (beginning-of-line) + (kill-whole-line) + (backward-char) + (LaTeX--make-inline-finalize-region start (point) delims)))))))) + +(defun LaTeX--make-inline-finalize-region (start end delims) + "Finalize the inline conversion from START to END using DELIMS." + (save-restriction + (narrow-to-region start end) + + (goto-char (point-min)) + (let ((re (concat "\\(?:" + (if (bound-and-true-p reftex-label-regexps) + (mapconcat #'identity reftex-label-regexps "\\|") + "\\\\label{[^}]*}") + "\\)"))) + (while (re-search-forward re nil t) + (replace-match ""))) + + (goto-char (point-min)) + (while (looking-at "\\s-*$") + (delete-line)) + (beginning-of-line-text) + (delete-region (point-min) (point)) + + (goto-char (point-max)) + (while (and (> (point) (point-min)) + (progn (forward-line -1) + (looking-at "\\s-*$"))) + (delete-line)) + (end-of-line) + (skip-chars-backward " \t") + (delete-region (point) (point-max)) + + (goto-char (point-min)) + (insert (car delims)) + (goto-char (point-max)) + + (while (looking-back "[.,;:!?]" (max (point-min) (- (point) 5))) + (backward-char)) + (insert (cdr delims)) + + (while (> (count-lines (point-min) (point-max)) 1) + (join-line))) + (join-line)) + (provide 'latex) ;;; latex.el ends here diff --git a/tests/latex/latex-make-inline-test.el b/tests/latex/latex-make-inline-test.el new file mode 100644 index 00000000..f4dbadf0 --- /dev/null +++ b/tests/latex/latex-make-inline-test.el @@ -0,0 +1,79 @@ +;;; latex-make-inline-test.el --- tests for LaTeX-make-inline -*- lexical-binding: t; -*- + +;; Copyright (C) 2025 Free Software Foundation, Inc. + +;; This file is part of AUCTeX. + +;; AUCTeX is free software; you can redistribute it and/or modify it +;; under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. + +;; AUCTeX is distributed in the hope that it will be useful, but +;; WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with AUCTeX; see the file COPYING. If not, write to the Free +;; Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +;; 02110-1301, USA. + +;;; Code: + +(require 'ert) +(require 'cl-lib) +(require 'latex) + +(defmacro latex-make-inline-test--with-temp-buffer (contents &rest body) + (declare (indent 1) (debug t)) + `(with-temp-buffer + (LaTeX-mode) + (insert ,contents) + (goto-char (point-min)) + (cl-letf (((symbol-function 'preview-clearout-at-point) #'ignore)) + ,@body))) + +(ert-deftest LaTeX-make-inline-bracket-period () + "Convert \\[..\\] to $..$ and keep trailing period." + (latex-make-inline-test--with-temp-buffer + "We have\n\\[ a+b = c. \\]" + (search-forward "b") + (LaTeX-make-inline) + (should (equal (buffer-string) "We have $a+b = c$.")))) + +(ert-deftest LaTeX-make-inline-double-dollar () + "Convert $$..$$ to $..$." + (latex-make-inline-test--with-temp-buffer + "$$x!$$" + (search-forward "x") + (LaTeX-make-inline) + (should (equal (buffer-string) "$x$!")))) + +(ert-deftest LaTeX-make-inline-electric-math () + "Respect `TeX-electric-math'." + (let ((TeX-electric-math '("\\(" . "\\)"))) + (latex-make-inline-test--with-temp-buffer + "\\[ x \\]" + (search-forward "x") + (LaTeX-make-inline) + (should (equal (buffer-string) "\\(x\\)"))))) + +(ert-deftest LaTeX-make-inline-equation-env () + "Convert equation environment, drop \\label, keep comma." + (latex-make-inline-test--with-temp-buffer + "\\begin{equation}\n\\label{l}x+y,\n\\end{equation}\n" + (search-forward "x") + (let ((TeX-electric-math '("\\(" . "\\)"))) + (LaTeX-make-inline) + (should (equal (buffer-string) "\\(x+y\\),\n"))))) + +(ert-deftest LaTeX-make-inline-noop () + "Call inside inline math leaves buffer unchanged." + (latex-make-inline-test--with-temp-buffer + "Already $z$ inline." + (search-forward "z") + (LaTeX-make-inline) + (should (equal (buffer-string) "Already $z$ inline.")))) + +;;; latex-make-inline-test.el ends here -- 2.39.3 (Apple Git-145) --=-=-=-- From unknown Sat Jun 14 19:44:59 2025 X-Loop: help-debbugs@gnu.org Subject: bug#78586: TeX-make-inline Resent-From: Ikumi Keita Original-Sender: "Debbugs-submit" Resent-CC: bug-auctex@gnu.org Resent-Date: Fri, 30 May 2025 07:01:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 78586 X-GNU-PR-Package: auctex X-GNU-PR-Keywords: To: "Paul D. Nelson" Cc: arash@gnu.org, 78586@debbugs.gnu.org Received: via spool by 78586-submit@debbugs.gnu.org id=B78586.17485884608607 (code B ref 78586); Fri, 30 May 2025 07:01:02 +0000 Received: (at 78586) by debbugs.gnu.org; 30 May 2025 07:01:00 +0000 Received: from localhost ([127.0.0.1]:44617 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1uKtjg-0002EB-63 for submit@debbugs.gnu.org; Fri, 30 May 2025 03:01:00 -0400 Received: from smtp1a.inetd.co.jp ([210.129.88.11]:52228) by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.84_2) (envelope-from ) id 1uKtjd-00022M-26 for 78586@debbugs.gnu.org; Fri, 30 May 2025 03:00:58 -0400 Received: from localhost (42-144-37-89.rev.home.ne.jp [42.144.37.89]) by smtp1a.inetd.co.jp (Postfix) with ESMTPSA id 72F6C8A; Fri, 30 May 2025 16:00:53 +0900 (JST) From: Ikumi Keita In-reply-to: References: Comments: In-reply-to "Paul D. Nelson" message dated "Thu, 29 May 2025 20:47:55 +0200." X-Mailer: MH-E 8.6+git; nmh 1.8; Emacs 30.1 MIME-Version: 1.0 Content-Type: text/plain; charset=iso-2022-jp Date: Fri, 30 May 2025 16:00:52 +0900 Message-ID: <10409.1748588452@localhost> X-Spam-Score: 0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Hi Paul, >>>>> "Paul D. Nelson" writes: > Thanks Ikuya, good catch! Please find attached the updated patch. Paul > +(defun LaTeX-make-inline () > + "Convert LaTeX display math environment at point to inline math. > +Remove the enclosing math environment (such as \\\\=[...\\\\=] or That works but I recommend \\=\\[ rather than \\\\=[ . See (elisp) Keys in Documentation: ,---- | ‘\=’ | quotes the following character and is discarded; thus, ‘\=`’ puts | ‘`’ into the output, ‘\=\[’ puts ‘\[’ into the output, and ‘\=\=’ | puts ‘\=’ into the output. `---- And you don't have to quote \]. It will be displayed literally. Additionally, we should provide similar quotation in > +(ert-deftest LaTeX-make-inline-bracket-period () > + "Convert \\[..\\] to $..$ and keep trailing period." as well. Bye, Ikumi Keita #StandWithUkraine #StopWarInUkraine #Gaza #StopMassiveKilling #CeasefireNOW From unknown Sat Jun 14 19:44:59 2025 X-Loop: help-debbugs@gnu.org Subject: bug#78586: TeX-make-inline References: Resent-From: "Paul D. Nelson" Original-Sender: "Debbugs-submit" Resent-CC: bug-auctex@gnu.org Resent-Date: Sat, 31 May 2025 14:58:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 78586 X-GNU-PR-Package: auctex X-GNU-PR-Keywords: To: Ikumi Keita Cc: arash@gnu.org, 78586@debbugs.gnu.org Received: via spool by 78586-submit@debbugs.gnu.org id=B78586.17487034704394 (code B ref 78586); Sat, 31 May 2025 14:58:02 +0000 Received: (at 78586) by debbugs.gnu.org; 31 May 2025 14:57:50 +0000 Received: from localhost ([127.0.0.1]:58790 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1uLNee-00018k-M3 for submit@debbugs.gnu.org; Sat, 31 May 2025 10:57:50 -0400 Received: from mail-lf1-x130.google.com ([2a00:1450:4864:20::130]:54645) by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.84_2) (envelope-from ) id 1uLNea-000184-4o for 78586@debbugs.gnu.org; Sat, 31 May 2025 10:57:46 -0400 Received: by mail-lf1-x130.google.com with SMTP id 2adb3069b0e04-54b0d638e86so4509403e87.1 for <78586@debbugs.gnu.org>; Sat, 31 May 2025 07:57:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1748703458; x=1749308258; darn=debbugs.gnu.org; h=mime-version:message-id:date:in-reply-to:subject:cc:to:from:from:to :cc:subject:date:message-id:reply-to; bh=qVoPF8jOVAZqzO+rYHQ+4zdyH02QpsgZPOKSyA8BxXo=; b=FEmYk9igyZMoF2ipSAov3JDuIczoyJkDW73pD2YK4vLAme0l6nPh4EMjd2SH2GPJca d3Wu6ZgWSs2F2cc6120cvMNtvzxeaUXtIaTAHKM7OHvHgF1jrW4rRw28pW+AyagHs+tf hbtnklbYhfBsW7TBbCME/349pnzxklicvWWHCuKaC920wzTm8f+7HXmVMKwhNj1gtCeb GPUt0G51dzqVe1sExVzPMOhjJbAGcw/T2AvbPcMzWN26s6jMFIL8G+WIuBd9sXRuHvC0 0ku2+JrbeOEX2pi28r+KDFkwK4Jobj0WEXn+zqqO/YTZqn4u17QH8keS0p53xdXYbncs jzEQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1748703458; x=1749308258; h=mime-version:message-id:date:in-reply-to:subject:cc:to:from :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=qVoPF8jOVAZqzO+rYHQ+4zdyH02QpsgZPOKSyA8BxXo=; b=AABU1F4QjNg0QY//2oLi9vX393eBIQtAbL7wUvVEdikJDMEpz3H4QZmVL3d2lsPY7P Jvro/n8cVqMe1TU+XLEi7DY3LhksyHuZWo5dJE7XTy6vXz3Kra6F+/sN2jAbgCkI+ZP5 FQRdIkacJ1YeWyyyKcbDuj3FH3V41fIF3aoDaTgWGx6AiRUF97vi/Te0x5TRj8gl6zha Hwox4XQD+poanmdIS5XRvVWAmWVInEuuFf02Rp3cCvgv9SrbNfitBp8yNHKw+JmFXuC3 YGG1yRSMoAP0FRTFTVQYPK81Y3X8w+EZs7clTOFv/BrDGxWoSP0eXGSeFmwsORfkfgh/ rs5w== X-Forwarded-Encrypted: i=1; AJvYcCWquSq+L6VmOzGIdUOqyR397OwBUh8XRslHjkIi/w0QKpPsye958CqDwyPR9sfHPClzVtfwOQ==@debbugs.gnu.org X-Gm-Message-State: AOJu0YwU+vs3PuYxcJkgCwTDTyuZU6tYyb5MkJleuKInMJ9jg1OcNih+ wA/TSX6hhu2u/tQGzMszRlruwdHM6/M5vvSfDNihRl+ML4DsqvYFvQoFWf7S4iZz X-Gm-Gg: ASbGncs+ERL9TT9OfvAQ1RPPxTHBqsLVQ98FcjSKMeouRju4cYjiZeYj0TvMKgvu3mb AtSUPjzKZoH2jWC8luqVJZHFs/EkPOPIw0IJXjjgkG0F/eayQavXzibZYo0bfmA1XBvHYfZc50m rPrAsCp4e8qN3graCNFbMLBHo7NLyLlIzizW95bYK+1UTlxDTjx9PzJwW3Y5+Jn7dpHZrYDWXTF SHv5cpLgEKA8KyRPD7Po2/c7lnN72rrxsrK+4wepPJjYQA4qxTlOHOs01Y6FltPLQ0MA5XDA60R qcfu+aCztzWaLV6tpmIfe2lB4MuL43Avd9uvoCDPURiM0KjFHatq+hV0rHWls0/Ydl8F X-Google-Smtp-Source: AGHT+IFRJcBNu2ua0iX8jJD0V1unCxzq1JXrxzu9CQGffBDAENbzdJeRNEH99DBQ7ModLD4Fpt47Hg== X-Received: by 2002:a05:6512:1105:b0:553:2e4e:cf74 with SMTP id 2adb3069b0e04-5533d19df7fmr1794093e87.27.1748703457168; Sat, 31 May 2025 07:57:37 -0700 (PDT) Received: from localhost ([185.229.154.228]) by smtp.gmail.com with UTF8SMTPSA id 2adb3069b0e04-55337910308sm1065637e87.143.2025.05.31.07.57.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 31 May 2025 07:57:35 -0700 (PDT) From: "Paul D. Nelson" In-Reply-To: <10409.1748588452@localhost> (message from Ikumi Keita on Fri, 30 May 2025 16:00:52 +0900) Date: Sat, 31 May 2025 16:57:34 +0200 Message-ID: MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Spam-Score: 0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain Hi Ikumi, Thanks for the further feedback, which I've now incorporated. I mentioned that this was the first of several commands I planned to propose, in an attempt to upstream the most broadly useful stuff from https://github.com/ultronozm/czm-tex-edit.el. The next planned command was an "inverse" to LaTeX-make-inline, say LaTeX-make-display, that converts inline math to display math. I had planned to propose that command in a separate bug, but the two are so intertwined that I think it makes sense to treat them together. The tricky part in designing LaTeX-make-display is that different users may prefer different sorts of display math: \[..\], $$..$$, equation/equation*/align/align*/(...). Given that we don't want to add too many new user options, it seemed best to provide a general LaTeX-modify-math command, which the user can either invoke interactively or specialize like so: --8<---------------cut here---------------start------------->8--- (defun my-LaTeX-make-brackets () "Convert math construct at point to \"\\=\\[..\\=\\]\"." (interactive) (LaTeX-modify-math "\\[")) (defun my-LaTeX-make-equation* () "Convert math construct at point to \"equation*\"." (interactive) (LaTeX-modify-math "equation*")) (defun my-LaTeX-toggle-numbered () "Convert math construct at point to \"equation*\". If the math construct is already \"equation*\", then toggle with the numbered variant \"equation\"." (interactive) (unless (texmathp) (user-error "Not inside math")) (let ((current (car texmathp-why))) (LaTeX-modify-math (pcase current ("equation*" "equation") ("equation" "equation*") (_ "equation*"))))) (defun my-LaTeX-toggle-align () "Toggle math environment at point between \"equation\" and \"align\"." (interactive) (unless (texmathp) (user-error "Not inside math")) (let ((current (car texmathp-why))) (LaTeX-modify-math (pcase current ("align*" "equation*") ("equation*" "align*") ("align" "equation") ("equation" "align") (_ "align*"))))) --8<---------------cut here---------------end--------------->8--- We could document some of these in the manual (where?), but leave their precise implementation and binding to the user. How does this plan sound? The attached patch contains everything but documentation concerning LaTeX-modify-math, for which I await feedback on a location in the manual and the overall soundness of the approach. Thanks, best, Paul --=-=-= Content-Type: text/x-patch; charset=utf-8 Content-Disposition: attachment; filename=0001-Add-LaTeX-modify-math-and-LaTeX-make-inline.patch Content-Transfer-Encoding: quoted-printable >From 2bbfcad353be520f91496ce131830495541ddf04 Mon Sep 17 00:00:00 2001 From: Paul Nelson Date: Thu, 29 May 2025 11:14:11 +0200 Subject: [PATCH] Add LaTeX-modify-math and LaTeX-make-inline * latex.el (LaTeX--modify-math-1, LaTeX--closing): New helper functions. (LaTeX-modify-math, LaTeX-make-inline): New commands. * tests/latex/latex-modify-math-test.el: New test file. (latex-make-inline-test--with-temp-buffer): New test macro. (LaTeX-modify-math-inline-bracket-period) (LaTeX-modify-math-inline-double-dollar) (LaTeX-modify-math-inline-electric-math) (LaTeX-modify-math-inline-equation-env) (LaTeX-modify-math-inline-noop) (LaTeX-modify-math-inline-paren-to-dollar) (LaTeX-modify-math-inline-multiline-equation) (LaTeX-modify-math-inline-punctuation-semicolon) (LaTeX-modify-math-inline-multiple-punctuation) (LaTeX-modify-math-inline-whitespace-preservation) (LaTeX-modify-math-inline-empty-lines) (LaTeX-modify-math-dollar-to-bracket) (LaTeX-modify-math-paren-to-double-dollar) (LaTeX-modify-math-bracket-to-equation) (LaTeX-modify-math-point-inline-to-display-after-content) (LaTeX-modify-math-point-inline-to-display-before-content) (LaTeX-modify-math-point-display-to-inline-after-content) (LaTeX-modify-math-point-display-to-inline-before-content) (LaTeX-modify-math-point-multiline-roundtrip): New test cases. * doc/auctex.texi (Quotes): Document LaTeX-make-inline. --- doc/auctex.texi | 10 ++ latex.el | 187 ++++++++++++++++++++++++ tests/latex/latex-modify-math-test.el | 203 ++++++++++++++++++++++++++ 3 files changed, 400 insertions(+) create mode 100644 tests/latex/latex-modify-math-test.el diff --git a/doc/auctex.texi b/doc/auctex.texi index 0b486c8c..9602c062 100644 --- a/doc/auctex.texi +++ b/doc/auctex.texi @@ -484,6 +484,16 @@ to prevent unmatched dollar. Note that Texinfo mode does nothing special for @kbd{$}. It inserts dollar sign(s) just in the same way as the other normal keys do. =20 +@AUCTeX{} provides the command @code{LaTeX-make-inline} which converts the +display math environment at point to inline math. + +@deffn Command LaTeX-make-inline +Convert @LaTeX{} display math environment at point to inline math. This +command replaces the enclosing math environment such as @samp{\[...\]} or +@samp{\begin@{equation@}...\end@{equation@}} with the value of +@code{TeX-electric-math} or @samp{$...$} by default. +@end deffn + @subheading Braces =20 To avoid unbalanced braces, it is useful to insert them pairwise. You diff --git a/latex.el b/latex.el index 797513f2..f6cc5b9d 100644 --- a/latex.el +++ b/latex.el @@ -9551,6 +9551,193 @@ no caption key is found, an error is issued. See a= lso the docstring of "LARGE" "huge" "Huge") "List of LaTeX font size declarations.") =20 +(defun LaTeX--modify-math-1 (open close inline new-open new-close new-inli= ne pos) + "Helper function for `LaTeX-modify-math'. +OPEN and CLOSE are the current delimiters, NEW-OPEN and NEW-CLOSE are +the new delimiters. INLINE and NEW-INLINE are booleans indicating +whether the current and new delimiters are inline or display math. +Assume point is at the start of the current OPEN delimiter. POS is a +marker that keeps track of cursor position." + (let ((converting-to-inline (and (not inline) new-inline))) + (when converting-to-inline + ;; Join with previous line if non-blank. + (when (and (looking-back "\n[[:blank:]]*" (point-min)) + (> (line-beginning-position) (point-min)) + (save-excursion + (forward-line -1) + (not (looking-at "^[[:blank:]]*$")))) + (forward-char (length open)) + (save-excursion (join-line)) + (forward-char (- (length open))))) + (unless new-inline + ;; Ensure non-inline delimiters start on a blank line. + (unless (looking-back "\n[[:blank:]]*" (point-min)) + (delete-horizontal-space) + (insert "\n"))) + ;; Delete opening delimiter. + (delete-char (length open)) + (let ((start (point))) + (search-forward close) + (when converting-to-inline + ;; Join with next line if non-blank. + (when (and (looking-at-p "[[:blank:]]*\n") + (< (line-end-position) (point-max)) + (save-excursion + (forward-line 1) + (not (looking-at-p "^[[:blank:]]*$")))) + (join-line 'next))) + (unless new-inline + (unless (looking-at-p "[[:blank:]]*\n") + (save-excursion + (insert "\n")))) + ;; Delete closing delimiter. + (delete-char (- (length close))) + (save-restriction + (narrow-to-region start (point)) + ;; Clear labels. + (goto-char (point-min)) + (let ((re (concat + "\\(?:" + (if (bound-and-true-p reftex-label-regexps) + (mapconcat #'identity reftex-label-regexps "\\|") + (format "%slabel%s%s%s" + (regexp-quote TeX-esc) + TeX-grop "[^}]*" TeX-grcl)) + "\\)"))) + (while (re-search-forward re nil t) + (replace-match ""))) + ;; Delete leading and trailing whitespace. + (dolist (re '("\\`[ \t\n\r]+" "[ \t\n\r]+\\'")) + (goto-char (point-min)) + (when (re-search-forward re nil t) + (replace-match ""))) + (unless new-inline + (goto-char (point-min)) + (insert "\n") + (goto-char (point-max)) + (insert "\n")) + ;; Insert new opening delimiter. + (goto-char (point-min)) + (insert new-open) + ;; Insert new closing delimiter + (goto-char (point-max)) + (when (eq (point) (marker-position pos)) + (set-marker-insertion-type pos (not 'advance))) + (when converting-to-inline + ;; Leave punctuation outside. + (while (looking-back "[.,;:!?]" + (max (point-min) (- (point) 5))) + (backward-char))) + (insert new-close) + ;; Indent, including one line past the modified region. + (widen) + (end-of-line 2) + (indent-region start (point)))))) + +(defun LaTeX--closing (type) + "Return closing delimiter corresponding to given `texmathp' TYPE. +TYPE must be one of the (La)TeX symbols $, $$, \\( or \\=3D\\[, or a valid +environment name. Macros such as \\ensuremath are not supported." + (pcase type + ((or "$" "$$") type) + ("\\[" "\\]") + ("\\(" "\\)") + (_ (unless (assoc type (LaTeX-environment-list-filtered)) + (error "Invalid or unsupported opening delimiter: %s" type)) + (concat TeX-esc "end" TeX-grop type TeX-grcl)))) + +(defun LaTeX-modify-math (&optional new-type) + "Modify the current math construct to NEW-TYPE. + +Interactively, prompt for NEW-TYPE from a list of inline math +delimiters (\"$\", \"\\(\"), display math delimiters (\"$$\", +\"\\=3D\\[\") and valid LaTeX environments (\"equation\", ...). + +Non-interactively, NEW-TYPE must be either +- a string specifying the target delimiter or environment name, or +- a cons cell ((OPEN . CLOSE) . INLINE), where OPEN and CLOSE are + delimiters and INLINE is non-nil if the math construct is to be + understood as inline. + +The function converts the math construct at point (inline, display, or +environment) to the specified NEW-TYPE, preserving the content. If +point is not in a math construct, signal an error. Clears any active +previews at point before modification. + +Does not support modifying macro-based constructs such as \\ensuremath." + (interactive + (let* ((type (progn (texmathp) (car texmathp-why))) + (tbl (append '("$" "\\(" "$$" "\\[") + (LaTeX-environment-list-filtered)))) + (unless type (user-error "Not inside math")) + (LaTeX--closing type) ;; Check for errors. + (list (completing-read + (format "Convert %s =E2=86=92 " type) tbl nil t nil nil + type)))) + (let ((new-open (if (stringp new-type) + new-type + (caar new-type))) + (new-close (if (stringp new-type) + (LaTeX--closing new-type) + (cdar new-type))) + (new-inline (if (stringp new-type) + (member new-type '("$" "\\(")) + (cdr new-type)))) + (when (fboundp 'preview-clearout-at-point) + (preview-clearout-at-point)) + (unless (called-interactively-p 'any) + (unless (texmathp) (error "Not inside math"))) + (let ((type (car texmathp-why)) + (math-start (cdr texmathp-why)) + (pos (point-marker))) + (set-marker-insertion-type pos + (not + (and + (< (point) (point-max)) + (save-excursion + (forward-char) + (not (texmathp)))))) + (goto-char math-start) + (let* ((open (if (member type '("\\(" "$" "\\[" "$$")) + type + (concat TeX-esc "begin" TeX-grop type TeX-grcl))) + (close (LaTeX--closing type))) + (if (or (not (stringp new-type)) + (member new-open '("$" "\\(" "\\[" "$$"))) + ;; Conversion to inline or non-environment display. + (let* ((inline (member type '("$" "\\(")))) + (LaTeX--modify-math-1 open close inline new-open new-close n= ew-inline pos)) + ;; Conversion to an environment. + (if (member type '("$" "\\(" "$$" "\\[")) + (delete-char (length type)) + (kill-line)) + (push-mark (save-excursion + (search-forward close) + (delete-region (match-beginning 0) (match-end 0)) + (when (eq (point) (marker-position pos)) + (setq pos nil)) + (when (member type '("$" "\\(")) + (while (looking-at-p "[.,;:!?]") + (forward-char))) + (point))) + (activate-mark) + (LaTeX-insert-environment new-type))) + (when pos + (goto-char pos))))) + +(defun LaTeX-make-inline () + "Convert LaTeX display math construct at point to inline math. +Remove the enclosing math construct (such as \\=3D\\[...\\=3D\\] or +\\begin{equation}...\\end{equation}) and replace it with inline math +surrounded by `TeX-electric-math' if non-nil, or \"$...$\", fitting the +result onto one line. Finally, leave any trailing punctuation outside +the math delimiters." + (interactive) + (LaTeX-modify-math + (if TeX-electric-math + (cons TeX-electric-math 'inline) + "$"))) + (provide 'latex) =20 ;;; latex.el ends here diff --git a/tests/latex/latex-modify-math-test.el b/tests/latex/latex-modi= fy-math-test.el new file mode 100644 index 00000000..f50d9ae3 --- /dev/null +++ b/tests/latex/latex-modify-math-test.el @@ -0,0 +1,203 @@ +;;; latex-modify-math-test.el --- tests for LaTeX-make-inline -*- lexical= -binding: t; -*- + +;; Copyright (C) 2025 Free Software Foundation, Inc. + +;; This file is part of AUCTeX. + +;; AUCTeX is free software; you can redistribute it and/or modify it +;; under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. + +;; AUCTeX is distributed in the hope that it will be useful, but +;; WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with AUCTeX; see the file COPYING. If not, write to the Free +;; Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +;; 02110-1301, USA. + +;;; Code: + +(require 'ert) +(require 'cl-lib) +(require 'latex) + +(defmacro latex-modify-test--with-temp-buffer (contents &rest body) + "Create a temporary LaTeX buffer with CONTENTS and execute BODY. +This macro is used to set up a test environment for `LaTeX-modify-math'." + (declare (indent 1) (debug t)) + `(with-temp-buffer + (LaTeX-mode) + (insert ,contents) + (goto-char (point-min)) + (cl-letf (((symbol-function 'preview-clearout-at-point) #'ignore)) + ,@body))) + +(ert-deftest LaTeX-modify-math-inline-bracket-period () + "Convert \\=3D\\[...\\=3D\\] to $..$ and keep trailing period." + (latex-modify-test--with-temp-buffer + "We have\n\\[ a+b =3D c. \\]" + (search-forward "b") + (LaTeX-make-inline) + (should (equal (buffer-string) "We have $a+b =3D c$.")))) + +(ert-deftest LaTeX-modify-math-inline-double-dollar () + "Convert $$..$$ to $..$." + (latex-modify-test--with-temp-buffer + "$$x!$$" + (search-forward "x") + (LaTeX-make-inline) + (should (equal (buffer-string) "$x$!")))) + +(ert-deftest LaTeX-modify-math-inline-electric-math () + "Respect `TeX-electric-math'." + (let ((TeX-electric-math '("\\(" . "\\)"))) + (latex-modify-test--with-temp-buffer + "\\[ x \\]" + (search-forward "x") + (LaTeX-make-inline) + (should (equal (buffer-string) "\\(x\\)"))))) + +(ert-deftest LaTeX-modify-math-inline-equation-env () + "Convert equation environment, drop \\label, keep comma." + (latex-modify-test--with-temp-buffer + "Hi.\n\nWe have\n\\begin{equation}\n\\label{l}x+y,\n\\end{equation}\= n" + (search-forward "x") + (let ((TeX-electric-math '("\\(" . "\\)"))) + (LaTeX-make-inline) + (should (equal (buffer-string) "Hi.\n\nWe have \\(x+y\\),\n"))))) + +(ert-deftest LaTeX-modify-math-inline-noop () + "Call inside inline math leaves buffer unchanged." + (latex-modify-test--with-temp-buffer + "Already $z$ inline." + (search-forward "z") + (LaTeX-make-inline) + (should (equal (buffer-string) "Already $z$ inline.")))) + +(ert-deftest LaTeX-modify-math-inline-paren-to-dollar () + "Convert \\(...\\) to $...$." + (latex-modify-test--with-temp-buffer + "Text \\(a + b\\) more text." + (search-forward "a") + (let ((TeX-electric-math nil)) + (LaTeX-make-inline) + (should (equal (buffer-string) "Text $a + b$ more text."))))) + +(ert-deftest LaTeX-modify-math-inline-multiline-equation () + "Convert multiline equation environment to inline, removing labels." + (latex-modify-test--with-temp-buffer + "Before\n\\begin{equation}\n x + y =3D z\n \\label{eq:test}\n\\end= {equation}\nAfter" + (search-forward "x") + (LaTeX-make-inline) + (should (equal (buffer-string) "Before $x + y =3D z$ After")))) + +(ert-deftest LaTeX-modify-math-inline-punctuation-semicolon () + "Move semicolon outside inline math." + (latex-modify-test--with-temp-buffer + "\\[ x + y; \\]" + (search-forward "x") + (LaTeX-make-inline) + (should (equal (buffer-string) "$x + y$;")))) + +(ert-deftest LaTeX-modify-math-inline-multiple-punctuation () + "Handle multiple punctuation marks." + (latex-modify-test--with-temp-buffer + "\\[ result?! \\]" + (search-forward "result") + (LaTeX-make-inline) + (should (equal (buffer-string) "$result$?!")))) + +(ert-deftest LaTeX-modify-math-inline-whitespace-preservation () + "Preserve surrounding whitespace appropriately." + (latex-modify-test--with-temp-buffer + "Text \\[ a + b \\] more." + (search-forward "a") + (LaTeX-make-inline) + (should (equal (buffer-string) "Text $a + b$ more.")))) + +(ert-deftest LaTeX-modify-math-inline-empty-lines () + "Remove empty lines from display math when converting." + (latex-modify-test--with-temp-buffer + "\\[\n\n x =3D y \n\n\\]" + (search-forward "x") + (LaTeX-make-inline) + (should (equal (buffer-string) "$x =3D y$")))) + +(ert-deftest LaTeX-modify-math-dollar-to-bracket () + "Convert $...$ to \\=3D\\[...\\=3D\\]." + (latex-modify-test--with-temp-buffer + "Text $x + y$ more." + (search-forward "+") + (LaTeX-modify-math "\\[") + (should (equal (buffer-string) "Text\n\\[\n x + y\n\\]\nmore.")))) + +(ert-deftest LaTeX-modify-math-paren-to-double-dollar () + "Convert \\(...\\) to $$...$$." + (latex-modify-test--with-temp-buffer + "Text \\(a =3D b\\) end." + (search-forward "a") + (LaTeX-modify-math "$$") + (should (equal (buffer-string) "Text\n$$\na =3D b\n$$\nend.")))) + +(ert-deftest LaTeX-modify-math-bracket-to-equation () + "Convert \\=3D\\[...\\=3D\\] to equation environment." + (latex-modify-test--with-temp-buffer + "\\[ f(x) =3D x^2 \\]" + (search-forward "f") + (LaTeX-modify-math "equation") + (should (equal (buffer-string) "\\begin{equation}\n f(x) =3D x^2\n\\e= nd{equation}")))) + +(ert-deftest LaTeX-modify-math-point-inline-to-display-after-content () + "Point after inline content preserved after display conversion." + (latex-modify-test--with-temp-buffer + "A $x+y$ B" + (search-forward "y") + (LaTeX-modify-math "\\[") + (should (looking-back "y" (1- (point)))) + (should (looking-at "\n[[:space:]]*\\\\\\]")))) + +(ert-deftest LaTeX-modify-math-point-inline-to-display-before-content () + "Point before inline content preserved after display conversion." + (latex-modify-test--with-temp-buffer + "A $x+y$ B" + (search-forward "$") + (LaTeX-modify-math "\\[") + (looking-at "x") + (should (looking-at "x")))) + +(ert-deftest LaTeX-modify-math-point-display-to-inline-after-content () + "Point after display content preserved after inline conversion." + (latex-modify-test--with-temp-buffer + "\\[\n x + y\n\\]" + (goto-char (point-min)) + (re-search-forward "y") + (LaTeX-make-inline) + (should (looking-back "y" (1- (point)))) + (should (looking-at "\\$")))) + +(ert-deftest LaTeX-modify-math-point-display-to-inline-before-content () + "Point before display content preserved after inline conversion." + (latex-modify-test--with-temp-buffer + "\\[\n x + y\n\\]" + (goto-char (point-min)) + (re-search-forward "x") + (forward-char -1) + (LaTeX-make-inline) + (should (looking-at "x")))) + +(ert-deftest LaTeX-modify-math-point-multiline-roundtrip () + "Point before/after content preserved for round-trip conversion." + (latex-modify-test--with-temp-buffer + "foo $x+y$ bar" + (search-forward "y") + (backward-char) + (LaTeX-modify-math "\\[") + (should (looking-at "y")) + (LaTeX-make-inline) + (should (looking-at "y")))) + +;;; latex-modify-math-test.el ends here --=20 2.39.3 (Apple Git-145) --=-=-=-- From unknown Sat Jun 14 19:44:59 2025 X-Loop: help-debbugs@gnu.org Subject: bug#78586: TeX-make-inline Resent-From: Ikumi Keita Original-Sender: "Debbugs-submit" Resent-CC: bug-auctex@gnu.org Resent-Date: Mon, 02 Jun 2025 19:25:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 78586 X-GNU-PR-Package: auctex X-GNU-PR-Keywords: To: "Paul D. Nelson" Cc: arash@gnu.org, 78586@debbugs.gnu.org Received: via spool by 78586-submit@debbugs.gnu.org id=B78586.174889227619460 (code B ref 78586); Mon, 02 Jun 2025 19:25:02 +0000 Received: (at 78586) by debbugs.gnu.org; 2 Jun 2025 19:24:36 +0000 Received: from localhost ([127.0.0.1]:55152 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1uMAlv-00053i-Ch for submit@debbugs.gnu.org; Mon, 02 Jun 2025 15:24:36 -0400 Received: from smtp1a.inetd.co.jp ([210.129.88.11]:60270) by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.84_2) (envelope-from ) id 1uMAlr-00053H-Lh for 78586@debbugs.gnu.org; Mon, 02 Jun 2025 15:24:33 -0400 Received: from localhost (42-144-37-89.rev.home.ne.jp [42.144.37.89]) by smtp1a.inetd.co.jp (Postfix) with ESMTPSA id A44D75C; Tue, 3 Jun 2025 04:24:28 +0900 (JST) From: Ikumi Keita In-reply-to: References: Comments: In-reply-to "Paul D. Nelson" message dated "Sat, 31 May 2025 16:57:34 +0200." X-Mailer: MH-E 8.6+git; nmh 1.8; Emacs 30.1 MIME-Version: 1.0 Content-Type: text/plain; charset=iso-2022-jp Date: Tue, 03 Jun 2025 04:24:27 +0900 Message-ID: <3005.1748892267@localhost> X-Spam-Score: 0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Hi Paul, >>>>> "Paul D. Nelson" writes: > The next planned command was an "inverse" to LaTeX-make-inline, say > LaTeX-make-display, that converts inline math to display math. I had > planned to propose that command in a separate bug, but the two are so > intertwined that I think it makes sense to treat them together. > The tricky part in designing LaTeX-make-display is that different users > may prefer different sorts of display math: \[..\], $$..$$, > equation/equation*/align/align*/(...). Given that we don't want to add > too many new user options, it seemed best to provide a general > LaTeX-modify-math command, which the user can either invoke > interactively or specialize like so: > (defun my-LaTeX-make-brackets () [...] > How does this plan sound? The attached patch contains everything but > documentation concerning LaTeX-modify-math, for which I await feedback > on a location in the manual and the overall soundness of the approach. It seems interesting to me. I remember Uwe Brauer once requested such feature[1]. [1] https://lists.gnu.org/r/auctex-devel/2022-01/msg00010.html Here are my comments about your proposal. (I haven't acutually run the code, so I might be saying something very dumb, sorry): +(defun LaTeX--modify-math-1 (open close inline new-open new-close new-inline pos) + "Helper function for `LaTeX-modify-math'. +OPEN and CLOSE are the current delimiters, NEW-OPEN and NEW-CLOSE are +the new delimiters. INLINE and NEW-INLINE are booleans indicating +whether the current and new delimiters are inline or display math. +Assume point is at the start of the current OPEN delimiter. POS is a +marker that keeps track of cursor position." + (let ((converting-to-inline (and (not inline) new-inline))) + (when converting-to-inline + ;; Join with previous line if non-blank. + (when (and (looking-back "\n[[:blank:]]*" (point-min)) ... (1) + (> (line-beginning-position) (point-min)) ... (2) + (save-excursion + (forward-line -1) + (not (looking-at "^[[:blank:]]*$")))) I'd write the conditional for the second `when' as (save-excursion (skip-chars-backward "[:blank:]") (and (bolp) (not (bobp)) (progn (forward-char -1) (skip-chars-backward "[:blank:]") (not (bolp))))) because `looking-back' isn't efficient. However, this piece of code isn't as easy to read as yours, so you don't have to mind if you decide to reject it. Anyway, it seems to me that the condition (2) isn't needed because it is always satisfied when the condition (1) is met, if I don't miss something. + (forward-char (length open)) + (save-excursion (join-line)) + (forward-char (- (length open))))) + (unless new-inline + ;; Ensure non-inline delimiters start on a blank line. + (unless (looking-back "\n[[:blank:]]*" (point-min)) + (delete-horizontal-space) + (insert "\n"))) + ;; Delete opening delimiter. + (delete-char (length open)) + (let ((start (point))) + (search-forward close) + (when converting-to-inline + ;; Join with next line if non-blank. + (when (and (looking-at-p "[[:blank:]]*\n") + (< (line-end-position) (point-max)) ... (3) + (save-excursion + (forward-line 1) + (not (looking-at-p "^[[:blank:]]*$")))) Again, the condition (3) seems dispensable. + (join-line 'next))) + (unless new-inline + (unless (looking-at-p "[[:blank:]]*\n") + (save-excursion + (insert "\n")))) + ;; Delete closing delimiter. + (delete-char (- (length close))) + (save-restriction + (narrow-to-region start (point)) + ;; Clear labels. + (goto-char (point-min)) + (let ((re (concat + "\\(?:" + (if (bound-and-true-p reftex-label-regexps) + (mapconcat #'identity reftex-label-regexps "\\|") + (format "%slabel%s%s%s" + (regexp-quote TeX-esc) + TeX-grop "[^}]*" TeX-grcl)) + "\\)"))) + (while (re-search-forward re nil t) + (replace-match ""))) + ;; Delete leading and trailing whitespace. Is it really necessary to delete leading whitespaces? At the end of this function, we do `indent-region', which I expect would do the job. (And then, we can just call `delete-trailing-whitespace'.) + (dolist (re '("\\`[ \t\n\r]+" "[ \t\n\r]+\\'")) + (goto-char (point-min)) + (when (re-search-forward re nil t) + (replace-match ""))) + (unless new-inline + (goto-char (point-min)) + (insert "\n") + (goto-char (point-max)) + (insert "\n")) + ;; Insert new opening delimiter. + (goto-char (point-min)) + (insert new-open) + ;; Insert new closing delimiter + (goto-char (point-max)) + (when (eq (point) (marker-position pos)) We can simplify the conditional as (= (point) pos) + (set-marker-insertion-type pos (not 'advance))) + (when converting-to-inline + ;; Leave punctuation outside. + (while (looking-back "[.,;:!?]" + (max (point-min) (- (point) 5))) + (backward-char))) We can use `skip-chars-backward' instead of the `while' loop. + (insert new-close) + ;; Indent, including one line past the modified region. + (widen) + (end-of-line 2) + (indent-region start (point)))))) + +(defun LaTeX--closing (type) + "Return closing delimiter corresponding to given `texmathp' TYPE. +TYPE must be one of the (La)TeX symbols $, $$, \\( or \\=\\[, or a valid +environment name. Macros such as \\ensuremath are not supported." + (pcase type + ((or "$" "$$") type) + ("\\[" "\\]") + ("\\(" "\\)") + (_ (unless (assoc type (LaTeX-environment-list-filtered)) + (error "Invalid or unsupported opening delimiter: %s" type)) + (concat TeX-esc "end" TeX-grop type TeX-grcl)))) + +(defun LaTeX-modify-math (&optional new-type) Why do you make the `new-type' argument optional? It is always non-nil when called interactively, and must be non-nil when called in program according to the following doc string. + "Modify the current math construct to NEW-TYPE. + +Interactively, prompt for NEW-TYPE from a list of inline math +delimiters (\"$\", \"\\(\"), display math delimiters (\"$$\", +\"\\=\\[\") and valid LaTeX environments (\"equation\", ...). + +Non-interactively, NEW-TYPE must be either +- a string specifying the target delimiter or environment name, or +- a cons cell ((OPEN . CLOSE) . INLINE), where OPEN and CLOSE are + delimiters and INLINE is non-nil if the math construct is to be + understood as inline. + +The function converts the math construct at point (inline, display, or +environment) to the specified NEW-TYPE, preserving the content. If +point is not in a math construct, signal an error. Clears any active +previews at point before modification. + +Does not support modifying macro-based constructs such as \\ensuremath." + (interactive + (let* ((type (progn (texmathp) (car texmathp-why))) + (tbl (append '("$" "\\(" "$$" "\\[") + (LaTeX-environment-list-filtered)))) + (unless type (user-error "Not inside math")) + (LaTeX--closing type) ;; Check for errors. + (list (completing-read + (format "Convert %s → " type) tbl nil t nil nil + type)))) + (let ((new-open (if (stringp new-type) + new-type + (caar new-type))) + (new-close (if (stringp new-type) + (LaTeX--closing new-type) + (cdar new-type))) + (new-inline (if (stringp new-type) + (member new-type '("$" "\\(")) + (cdr new-type)))) + (when (fboundp 'preview-clearout-at-point) + (preview-clearout-at-point)) + (unless (called-interactively-p 'any) + (unless (texmathp) (error "Not inside math"))) + (let ((type (car texmathp-why)) + (math-start (cdr texmathp-why)) + (pos (point-marker))) + (set-marker-insertion-type pos + (not + (and + (< (point) (point-max)) + (save-excursion + (forward-char) + (not (texmathp)))))) + (goto-char math-start) + (let* ((open (if (member type '("\\(" "$" "\\[" "$$")) + type + (concat TeX-esc "begin" TeX-grop type TeX-grcl))) + (close (LaTeX--closing type))) + (if (or (not (stringp new-type)) + (member new-open '("$" "\\(" "\\[" "$$"))) + ;; Conversion to inline or non-environment display. + (let* ((inline (member type '("$" "\\(")))) + (LaTeX--modify-math-1 open close inline new-open new-close new-inline pos)) + ;; Conversion to an environment. + (if (member type '("$" "\\(" "$$" "\\[")) + (delete-char (length type)) + (kill-line)) + (push-mark (save-excursion + (search-forward close) + (delete-region (match-beginning 0) (match-end 0)) + (when (eq (point) (marker-position pos)) Again, we can do (= (point) pos) here. + (setq pos nil)) I recommend to do (set-marker pos nil) before throwing away a temporal marker. See (elisp) Overview of Markers: ,---- | Insertion and deletion in a buffer must check all the markers and | relocate them if necessary. This slows processing in a buffer with a | large number of markers. For this reason, it is a good idea to make a | marker point nowhere if you are sure you don't need it any more. | Markers that can no longer be accessed are eventually removed (*note | Garbage Collection::). `---- + (when (member type '("$" "\\(")) + (while (looking-at-p "[.,;:!?]") + (forward-char))) Again, we can use `skip-chars-forward' here. + (point))) + (activate-mark) + (LaTeX-insert-environment new-type))) + (when pos + (goto-char pos))))) Again, I recommend to do (set-marker pos nil) when a temporal marker finishes its job. + +(defun LaTeX-make-inline () + "Convert LaTeX display math construct at point to inline math. +Remove the enclosing math construct (such as \\=\\[...\\=\\] or +\\begin{equation}...\\end{equation}) and replace it with inline math +surrounded by `TeX-electric-math' if non-nil, or \"$...$\", fitting the +result onto one line. Finally, leave any trailing punctuation outside +the math delimiters." + (interactive) How about (interactive "*") instead? (Maybe we should consider to add (barf-if-buffer-read-only) in `LaTeX-modify-math' as well.) + (LaTeX-modify-math + (if TeX-electric-math + (cons TeX-electric-math 'inline) + "$"))) + Regards, Ikumi Keita #StandWithUkraine #StopWarInUkraine #Gaza #StopMassiveKilling #CeasefireNOW From unknown Sat Jun 14 19:44:59 2025 X-Loop: help-debbugs@gnu.org Subject: bug#78586: TeX-make-inline References: Resent-From: "Paul D. Nelson" Original-Sender: "Debbugs-submit" Resent-CC: bug-auctex@gnu.org Resent-Date: Tue, 03 Jun 2025 08:10:07 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 78586 X-GNU-PR-Package: auctex X-GNU-PR-Keywords: To: Ikumi Keita Cc: arash@gnu.org, 78586@debbugs.gnu.org Received: via spool by 78586-submit@debbugs.gnu.org id=B78586.174893816427904 (code B ref 78586); Tue, 03 Jun 2025 08:10:07 +0000 Received: (at 78586) by debbugs.gnu.org; 3 Jun 2025 08:09:24 +0000 Received: from localhost ([127.0.0.1]:59510 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1uMMi2-0007Fy-Ln for submit@debbugs.gnu.org; Tue, 03 Jun 2025 04:09:24 -0400 Received: from mail-lf1-x12a.google.com ([2a00:1450:4864:20::12a]:46518) by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.84_2) (envelope-from ) id 1uMMhp-0007Dp-Jc for 78586@debbugs.gnu.org; Tue, 03 Jun 2025 04:09:19 -0400 Received: by mail-lf1-x12a.google.com with SMTP id 2adb3069b0e04-55320ddb9edso5757085e87.1 for <78586@debbugs.gnu.org>; Tue, 03 Jun 2025 01:09:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1748938143; x=1749542943; darn=debbugs.gnu.org; h=mime-version:message-id:date:in-reply-to:subject:cc:to:from:from:to :cc:subject:date:message-id:reply-to; bh=p2IAJKEZPEyaGPqHZCW718D2HPi2DzI0XYNkwnRzJ+8=; b=MNwHFq8MBZ+DdlhKLftINVZDOWAMZKlcn4GBltbSDpA4ixPgkIS/Hug8u/+g6cKGsq deUj7kni7jiMJ/LbohDaJhf/L5KGDlnrb+UtDA2FE/2AaaarjanrW+bc/qQLgFZDpEhR 3Uh0Gfu9XP/sXUAMGf7gg57suyO4uIizBA2MPuf6k4JPGSCvB8nC9/stblW8MpKbFpxY prb/zNyVgiF7XvFPqaDeww4zT8CzM54rLk49oZ8J9HWC7zrDBI9ia2j60bZSiBomfpNZ 46l5zSuWq59HA9n4mZjXgd8YHmaoj3lemarPW1zZ4P4kIS5yWz1qQPTrGx25vfzYeann H1fg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1748938143; x=1749542943; h=mime-version:message-id:date:in-reply-to:subject:cc:to:from :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=p2IAJKEZPEyaGPqHZCW718D2HPi2DzI0XYNkwnRzJ+8=; b=gxEyVcP4dAhryyvQ6AfnwElwZRVVdX50+6P+eqEQRO1QZxr7WfwYthg94dTSqCeQ2Z 4qDQwjwp1gsya5kjSgrqTpYoabqpMjwvKE5+tqqJydF17rk5kSxnbJOfnOi/7yhgDK9I 8siPp3br7nBrITGAWBIfPi6kZtOWQ/dRd4RFAsj7h4Zh53qAZgSBqXqCS5xEVBYweB/G yBUHJec3O6z1HY10jQoCLfl/xhVjdxKOTBKHskn3tewnNJGeVPgiTfp5NZvLs+dVuJLB 21q0ebY8c2zNSMSpdBTxheS62wa3nK5BBtwO/dXDOHc5sQS7RB04pfjMqcdAO9aqwDpN jR+g== X-Forwarded-Encrypted: i=1; AJvYcCWB4TTovJ/kksZIfr2uGXaaamT6jtu/PuIFvFPQ99v17XZVnPQ1StO+mZcfX9GpLFaHJx4smA==@debbugs.gnu.org X-Gm-Message-State: AOJu0Yw9hcPV9250dnt8eD+yNBtxvaRWp3SPoo6P9HsplmLhCB2IsH+N NKVhLx7N1lpSatI0EqH5DmSq/j9s6H2D4nrPoHPLGavsydLRRbKc+JNW X-Gm-Gg: ASbGncsXKtItfNSydhPt6atbU9z/9d6ODMh2VO8GQdWIHxCiXk7gaRJmL/OOadxR2sy bIubwukCd6EYcbQ0Un7VqRr99Icet8Z3LNt3lc16QOKzxds8NM2Y7Y05hxOxGfb4vqPnyHLsXln e+PsVWmUUlsYHT3m2vviyfr2konapiF4HusLMYgJjDF1tIorhvdVAUf7tUrc5WyRbMlowyKi3pc glVbE2Bxn+O/AouEcJbUM3cCkWNMFFw8B6cY2dC1xtoAXoDXgKjaKfMGHlhv5b5VGiS412yt5/E LBcQ3eIhrwVTLMNHgh1ns4+wc8KLKIE33xMVDXQkUShhZB+uQzZgrAfhzS8xGcF7WfSUBG3Kesh 7z77nHx71LJDaIHvxjlILX/XnFzGfsFVmIdMdCg== X-Google-Smtp-Source: AGHT+IFxfM2xpFpOU+MN76A+bpgR54RRJ0ypPnjY6vPVig6TbPRuSSL4PUxMIOwfEHO4LIytT5yPvw== X-Received: by 2002:a05:6512:3510:b0:553:2f40:3715 with SMTP id 2adb3069b0e04-5533b8fb1d1mr3482625e87.15.1748938142603; Tue, 03 Jun 2025 01:09:02 -0700 (PDT) Received: from localhost (wlan-eduroam-130-237-240-27.su.se. [130.237.240.27]) by smtp.gmail.com with UTF8SMTPSA id 2adb3069b0e04-553378a12ecsm1831545e87.90.2025.06.03.01.09.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 03 Jun 2025 01:09:01 -0700 (PDT) From: "Paul D. Nelson" In-Reply-To: <3005.1748892267@localhost> (message from Ikumi Keita on Tue, 03 Jun 2025 04:24:27 +0900) Date: Tue, 03 Jun 2025 10:09:00 +0200 Message-ID: MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Spam-Score: 0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain Hi Ikumi, many thanks for your feedback. > Is it really necessary to delete leading whitespaces? At the end of this > function, we do `indent-region', which I expect would do the job. (And > then, we can just call `delete-trailing-whitespace'.) Deleting whitespace is relevant when converting from display to inline. It seemed like the appropriate way to handle the variety of ways users might write display math, e.g., $$ x + y $$ with or without newlines. Other suggestions would be welcome. I've incorporated all the other suggested changes, together with the following further changes: - replaced calls to LaTeX-environment-list-filtered with a new helper function LaTeX-math-environment-list (which could be made internal, I suppose?) that returns a more suitable list. - factored our a helper function LaTeX--strip-labels. Any further feedback welcome. Thanks, best, Paul --=-=-= Content-Type: text/x-patch; charset=utf-8 Content-Disposition: attachment; filename=0001-Add-LaTeX-modify-math-and-LaTeX-make-inline.patch Content-Transfer-Encoding: quoted-printable >From 8fe833bb6682d9270df48ba63cca8c72511fc35d Mon Sep 17 00:00:00 2001 From: Paul Nelson Date: Thu, 29 May 2025 11:14:11 +0200 Subject: [PATCH] Add LaTeX-modify-math and LaTeX-make-inline * latex.el (LaTeX--strip-labels, LaTeX--modify-math-1) (LaTeX--closing, LaTeX--math-environment-list): New helper functions. (LaTeX-modify-math, LaTeX-make-inline): New commands. * tests/latex/latex-modify-math-test.el: New test file. (latex-make-inline-test--with-temp-buffer): New test macro. (LaTeX-modify-math-inline-bracket-period) (LaTeX-modify-math-inline-double-dollar) (LaTeX-modify-math-inline-electric-math) (LaTeX-modify-math-inline-equation-env) (LaTeX-modify-math-inline-noop) (LaTeX-modify-math-inline-paren-to-dollar) (LaTeX-modify-math-inline-multiline-equation) (LaTeX-modify-math-inline-punctuation-semicolon) (LaTeX-modify-math-inline-multiple-punctuation) (LaTeX-modify-math-inline-whitespace-preservation) (LaTeX-modify-math-inline-empty-lines) (LaTeX-modify-math-dollar-to-bracket) (LaTeX-modify-math-paren-to-double-dollar) (LaTeX-modify-math-bracket-to-equation) (LaTeX-modify-math-point-inline-to-display-after-content) (LaTeX-modify-math-point-inline-to-display-before-content) (LaTeX-modify-math-point-display-to-inline-after-content) (LaTeX-modify-math-point-display-to-inline-before-content) (LaTeX-modify-math-point-multiline-roundtrip): New test cases. * doc/auctex.texi (Quotes): Document LaTeX-make-inline. --- doc/auctex.texi | 10 ++ latex.el | 203 ++++++++++++++++++++++++++ tests/latex/latex-modify-math-test.el | 203 ++++++++++++++++++++++++++ 3 files changed, 416 insertions(+) create mode 100644 tests/latex/latex-modify-math-test.el diff --git a/doc/auctex.texi b/doc/auctex.texi index 0b486c8c..9602c062 100644 --- a/doc/auctex.texi +++ b/doc/auctex.texi @@ -484,6 +484,16 @@ to prevent unmatched dollar. Note that Texinfo mode does nothing special for @kbd{$}. It inserts dollar sign(s) just in the same way as the other normal keys do. =20 +@AUCTeX{} provides the command @code{LaTeX-make-inline} which converts the +display math environment at point to inline math. + +@deffn Command LaTeX-make-inline +Convert @LaTeX{} display math environment at point to inline math. This +command replaces the enclosing math environment such as @samp{\[...\]} or +@samp{\begin@{equation@}...\end@{equation@}} with the value of +@code{TeX-electric-math} or @samp{$...$} by default. +@end deffn + @subheading Braces =20 To avoid unbalanced braces, it is useful to insert them pairwise. You diff --git a/latex.el b/latex.el index 797513f2..0c64155d 100644 --- a/latex.el +++ b/latex.el @@ -9551,6 +9551,209 @@ no caption key is found, an error is issued. See a= lso the docstring of "LARGE" "huge" "Huge") "List of LaTeX font size declarations.") =20 +(defun LaTeX--strip-labels () + "Remove label commands between point and end of buffer." + (let ((re (concat + "\\(?:" + (if (bound-and-true-p reftex-label-regexps) + (mapconcat #'identity reftex-label-regexps "\\|") + (format "%slabel%s%s%s" + (regexp-quote TeX-esc) + TeX-grop "[^}]*" TeX-grcl)) + "\\)"))) + (save-excursion + (while (re-search-forward re nil t) + (replace-match ""))))) + +(defun LaTeX--modify-math-1 (open close inline new-open new-close new-inli= ne pos) + "Helper function for `LaTeX-modify-math'. +OPEN and CLOSE are the current delimiters, NEW-OPEN and NEW-CLOSE are +the new delimiters. INLINE and NEW-INLINE are booleans indicating +whether the current and new delimiters are inline or display math. +Assume point is at the start of the current OPEN delimiter. POS is a +marker that keeps track of cursor position." + (let ((converting-to-inline (and (not inline) new-inline))) + (when converting-to-inline + ;; Join with previous line if non-blank. + (when (save-excursion + (skip-chars-backward "[:blank:]") + (and + (bolp) (not (bobp)) + (progn + (forward-char -1) + (skip-chars-backward "[:blank:]") + (not (bolp))))) + (forward-char (length open)) + (save-excursion (join-line)) + (forward-char (- (length open))))) + (unless new-inline + ;; Ensure non-inline delimiters start on a blank line. + (unless (save-excursion + (skip-chars-backward "[:blank:]") + (and + (bolp) (not (bobp)))) + (delete-horizontal-space) + (insert "\n"))) + ;; Delete opening delimiter. + (delete-char (length open)) + (let ((start (point))) + (search-forward close) + (when converting-to-inline + ;; Join with next line if non-blank. + (when (and (looking-at-p "[[:blank:]]*\n") + (save-excursion + (forward-line 1) + (not (looking-at-p "^[[:blank:]]*$")))) + (join-line 'next))) + (unless new-inline + (unless (looking-at-p "[[:blank:]]*\n") + (save-excursion + (insert "\n")))) + ;; Delete closing delimiter. + (delete-char (- (length close))) + (save-restriction + (narrow-to-region start (point)) + ;; Clear labels. + (goto-char (point-min)) + (LaTeX--strip-labels) + ;; Delete leading and trailing whitespace. + (dolist (re '("\\`[ \t\n\r]+" "[ \t\n\r]+\\'")) + (goto-char (point-min)) + (when (re-search-forward re nil t) + (replace-match ""))) + (unless new-inline + (goto-char (point-min)) + (insert "\n") + (goto-char (point-max)) + (insert "\n")) + ;; Insert new opening delimiter. + (goto-char (point-min)) + (insert new-open) + ;; Insert new closing delimiter + (goto-char (point-max)) + (when (=3D (point) pos) + (set-marker-insertion-type pos (not 'advance))) + (when converting-to-inline + (skip-chars-backward ".,;:!?")) + (insert new-close) + ;; Indent, including one line past the modified region. + (widen) + (end-of-line 2) + (indent-region start (point)))))) + +(defun LaTeX--math-environment-list () + "Return list of defined math environments. +This combines the env-on entries from `texmathp' and any user additions." + (texmathp-compile) + (mapcar #'car + (cl-remove-if-not + (lambda (entry) + (eq (nth 1 entry) 'env-on)) + texmathp-tex-commands1))) + +(defun LaTeX--closing (type) + "Return closing delimiter corresponding to given `texmathp' TYPE. +TYPE must be one of the (La)TeX symbols $, $$, \\( or \\=3D\\[, or a valid +environment name. Macros such as \\ensuremath are not supported." + (pcase type + ((or "$" "$$") type) + ("\\[" "\\]") + ("\\(" "\\)") + (_ (unless (member type (LaTeX--math-environment-list)) + (error "Invalid or unsupported opening delimiter: %s" type)) + (concat TeX-esc "end" TeX-grop type TeX-grcl)))) + +(defun LaTeX-modify-math (new-type) + "Modify the current math construct to NEW-TYPE. + +Interactively, prompt for NEW-TYPE from a list of inline math +delimiters (\"$\", \"\\(\"), display math delimiters (\"$$\", +\"\\=3D\\[\") and valid LaTeX environments (\"equation\", ...). + +Non-interactively, NEW-TYPE must be either +- a string specifying the target delimiter or environment name, or +- a cons cell ((OPEN . CLOSE) . INLINE), where OPEN and CLOSE are + delimiters and INLINE is non-nil if the math construct is to be + understood as inline. + +The function converts the math construct at point (inline, display, or +environment) to the specified NEW-TYPE, preserving the content. If +point is not in a math construct, signal an error. Clears any active +previews at point before modification. + +Does not support modifying macro-based constructs such as \\ensuremath." + (interactive + (let* ((type (progn (texmathp) (car texmathp-why))) + (tbl (append '("$" "\\(" "$$" "\\[") + (LaTeX--math-environment-list)))) + (barf-if-buffer-read-only) + (unless type (user-error "Not inside math")) + (LaTeX--closing type) ;; Check for errors. + (list (completing-read + (format "Convert %s =E2=86=92 " type) tbl nil t nil nil + type)))) + (let ((new-open (if (stringp new-type) + new-type + (caar new-type))) + (new-close (if (stringp new-type) + (LaTeX--closing new-type) + (cdar new-type))) + (new-inline (if (stringp new-type) + (member new-type '("$" "\\(")) + (cdr new-type)))) + (when (fboundp 'preview-clearout-at-point) + (preview-clearout-at-point)) + (unless (called-interactively-p 'any) + (unless (texmathp) (error "Not inside math"))) + (let ((type (car texmathp-why)) + (math-start (cdr texmathp-why)) + (pos (point-marker))) + (set-marker-insertion-type pos + (not + (and + (< (point) (point-max)) + (save-excursion + (forward-char) + (not (texmathp)))))) + (goto-char math-start) + (let* ((open (if (member type '("\\(" "$" "\\[" "$$")) + type + (concat TeX-esc "begin" TeX-grop type TeX-grcl))) + (close (LaTeX--closing type))) + (if (or (not (stringp new-type)) + (member new-open '("$" "\\(" "\\[" "$$"))) + ;; Conversion to inline or non-environment display. + (let* ((inline (member type '("$" "\\(")))) + (LaTeX--modify-math-1 open close inline new-open new-close n= ew-inline pos)) + ;; Conversion to an environment. + (delete-char (length open)) + (push-mark (save-excursion + (search-forward close) + (delete-region (match-beginning 0) (match-end 0)) + (when (=3D (point) pos) + (set-marker pos nil)) + (when (member type '("$" "\\(")) + (skip-chars-forward ".,;:!?")) + (point))) + (activate-mark) + (LaTeX-insert-environment new-type))) + (when pos + (goto-char pos) + (set-marker pos nil))))) + +(defun LaTeX-make-inline () + "Convert LaTeX display math construct at point to inline math. +Remove the enclosing math construct (such as \\=3D\\[...\\=3D\\] or +\\begin{equation}...\\end{equation}) and replace it with inline math +surrounded by `TeX-electric-math' if non-nil, or \"$...$\", fitting the +result onto one line. Finally, leave any trailing punctuation outside +the math delimiters." + (interactive "*") + (LaTeX-modify-math + (if TeX-electric-math + (cons TeX-electric-math 'inline) + "$"))) + (provide 'latex) =20 ;;; latex.el ends here diff --git a/tests/latex/latex-modify-math-test.el b/tests/latex/latex-modi= fy-math-test.el new file mode 100644 index 00000000..f50d9ae3 --- /dev/null +++ b/tests/latex/latex-modify-math-test.el @@ -0,0 +1,203 @@ +;;; latex-modify-math-test.el --- tests for LaTeX-make-inline -*- lexical= -binding: t; -*- + +;; Copyright (C) 2025 Free Software Foundation, Inc. + +;; This file is part of AUCTeX. + +;; AUCTeX is free software; you can redistribute it and/or modify it +;; under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. + +;; AUCTeX is distributed in the hope that it will be useful, but +;; WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with AUCTeX; see the file COPYING. If not, write to the Free +;; Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +;; 02110-1301, USA. + +;;; Code: + +(require 'ert) +(require 'cl-lib) +(require 'latex) + +(defmacro latex-modify-test--with-temp-buffer (contents &rest body) + "Create a temporary LaTeX buffer with CONTENTS and execute BODY. +This macro is used to set up a test environment for `LaTeX-modify-math'." + (declare (indent 1) (debug t)) + `(with-temp-buffer + (LaTeX-mode) + (insert ,contents) + (goto-char (point-min)) + (cl-letf (((symbol-function 'preview-clearout-at-point) #'ignore)) + ,@body))) + +(ert-deftest LaTeX-modify-math-inline-bracket-period () + "Convert \\=3D\\[...\\=3D\\] to $..$ and keep trailing period." + (latex-modify-test--with-temp-buffer + "We have\n\\[ a+b =3D c. \\]" + (search-forward "b") + (LaTeX-make-inline) + (should (equal (buffer-string) "We have $a+b =3D c$.")))) + +(ert-deftest LaTeX-modify-math-inline-double-dollar () + "Convert $$..$$ to $..$." + (latex-modify-test--with-temp-buffer + "$$x!$$" + (search-forward "x") + (LaTeX-make-inline) + (should (equal (buffer-string) "$x$!")))) + +(ert-deftest LaTeX-modify-math-inline-electric-math () + "Respect `TeX-electric-math'." + (let ((TeX-electric-math '("\\(" . "\\)"))) + (latex-modify-test--with-temp-buffer + "\\[ x \\]" + (search-forward "x") + (LaTeX-make-inline) + (should (equal (buffer-string) "\\(x\\)"))))) + +(ert-deftest LaTeX-modify-math-inline-equation-env () + "Convert equation environment, drop \\label, keep comma." + (latex-modify-test--with-temp-buffer + "Hi.\n\nWe have\n\\begin{equation}\n\\label{l}x+y,\n\\end{equation}\= n" + (search-forward "x") + (let ((TeX-electric-math '("\\(" . "\\)"))) + (LaTeX-make-inline) + (should (equal (buffer-string) "Hi.\n\nWe have \\(x+y\\),\n"))))) + +(ert-deftest LaTeX-modify-math-inline-noop () + "Call inside inline math leaves buffer unchanged." + (latex-modify-test--with-temp-buffer + "Already $z$ inline." + (search-forward "z") + (LaTeX-make-inline) + (should (equal (buffer-string) "Already $z$ inline.")))) + +(ert-deftest LaTeX-modify-math-inline-paren-to-dollar () + "Convert \\(...\\) to $...$." + (latex-modify-test--with-temp-buffer + "Text \\(a + b\\) more text." + (search-forward "a") + (let ((TeX-electric-math nil)) + (LaTeX-make-inline) + (should (equal (buffer-string) "Text $a + b$ more text."))))) + +(ert-deftest LaTeX-modify-math-inline-multiline-equation () + "Convert multiline equation environment to inline, removing labels." + (latex-modify-test--with-temp-buffer + "Before\n\\begin{equation}\n x + y =3D z\n \\label{eq:test}\n\\end= {equation}\nAfter" + (search-forward "x") + (LaTeX-make-inline) + (should (equal (buffer-string) "Before $x + y =3D z$ After")))) + +(ert-deftest LaTeX-modify-math-inline-punctuation-semicolon () + "Move semicolon outside inline math." + (latex-modify-test--with-temp-buffer + "\\[ x + y; \\]" + (search-forward "x") + (LaTeX-make-inline) + (should (equal (buffer-string) "$x + y$;")))) + +(ert-deftest LaTeX-modify-math-inline-multiple-punctuation () + "Handle multiple punctuation marks." + (latex-modify-test--with-temp-buffer + "\\[ result?! \\]" + (search-forward "result") + (LaTeX-make-inline) + (should (equal (buffer-string) "$result$?!")))) + +(ert-deftest LaTeX-modify-math-inline-whitespace-preservation () + "Preserve surrounding whitespace appropriately." + (latex-modify-test--with-temp-buffer + "Text \\[ a + b \\] more." + (search-forward "a") + (LaTeX-make-inline) + (should (equal (buffer-string) "Text $a + b$ more.")))) + +(ert-deftest LaTeX-modify-math-inline-empty-lines () + "Remove empty lines from display math when converting." + (latex-modify-test--with-temp-buffer + "\\[\n\n x =3D y \n\n\\]" + (search-forward "x") + (LaTeX-make-inline) + (should (equal (buffer-string) "$x =3D y$")))) + +(ert-deftest LaTeX-modify-math-dollar-to-bracket () + "Convert $...$ to \\=3D\\[...\\=3D\\]." + (latex-modify-test--with-temp-buffer + "Text $x + y$ more." + (search-forward "+") + (LaTeX-modify-math "\\[") + (should (equal (buffer-string) "Text\n\\[\n x + y\n\\]\nmore.")))) + +(ert-deftest LaTeX-modify-math-paren-to-double-dollar () + "Convert \\(...\\) to $$...$$." + (latex-modify-test--with-temp-buffer + "Text \\(a =3D b\\) end." + (search-forward "a") + (LaTeX-modify-math "$$") + (should (equal (buffer-string) "Text\n$$\na =3D b\n$$\nend.")))) + +(ert-deftest LaTeX-modify-math-bracket-to-equation () + "Convert \\=3D\\[...\\=3D\\] to equation environment." + (latex-modify-test--with-temp-buffer + "\\[ f(x) =3D x^2 \\]" + (search-forward "f") + (LaTeX-modify-math "equation") + (should (equal (buffer-string) "\\begin{equation}\n f(x) =3D x^2\n\\e= nd{equation}")))) + +(ert-deftest LaTeX-modify-math-point-inline-to-display-after-content () + "Point after inline content preserved after display conversion." + (latex-modify-test--with-temp-buffer + "A $x+y$ B" + (search-forward "y") + (LaTeX-modify-math "\\[") + (should (looking-back "y" (1- (point)))) + (should (looking-at "\n[[:space:]]*\\\\\\]")))) + +(ert-deftest LaTeX-modify-math-point-inline-to-display-before-content () + "Point before inline content preserved after display conversion." + (latex-modify-test--with-temp-buffer + "A $x+y$ B" + (search-forward "$") + (LaTeX-modify-math "\\[") + (looking-at "x") + (should (looking-at "x")))) + +(ert-deftest LaTeX-modify-math-point-display-to-inline-after-content () + "Point after display content preserved after inline conversion." + (latex-modify-test--with-temp-buffer + "\\[\n x + y\n\\]" + (goto-char (point-min)) + (re-search-forward "y") + (LaTeX-make-inline) + (should (looking-back "y" (1- (point)))) + (should (looking-at "\\$")))) + +(ert-deftest LaTeX-modify-math-point-display-to-inline-before-content () + "Point before display content preserved after inline conversion." + (latex-modify-test--with-temp-buffer + "\\[\n x + y\n\\]" + (goto-char (point-min)) + (re-search-forward "x") + (forward-char -1) + (LaTeX-make-inline) + (should (looking-at "x")))) + +(ert-deftest LaTeX-modify-math-point-multiline-roundtrip () + "Point before/after content preserved for round-trip conversion." + (latex-modify-test--with-temp-buffer + "foo $x+y$ bar" + (search-forward "y") + (backward-char) + (LaTeX-modify-math "\\[") + (should (looking-at "y")) + (LaTeX-make-inline) + (should (looking-at "y")))) + +;;; latex-modify-math-test.el ends here --=20 2.39.3 (Apple Git-145) --=-=-=-- From unknown Sat Jun 14 19:44:59 2025 X-Loop: help-debbugs@gnu.org Subject: bug#78586: TeX-make-inline Resent-From: Ikumi Keita Original-Sender: "Debbugs-submit" Resent-CC: bug-auctex@gnu.org Resent-Date: Wed, 04 Jun 2025 09:45:04 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 78586 X-GNU-PR-Package: auctex X-GNU-PR-Keywords: To: "Paul D. Nelson" Cc: arash@gnu.org, 78586@debbugs.gnu.org Received: via spool by 78586-submit@debbugs.gnu.org id=B78586.1749030258329 (code B ref 78586); Wed, 04 Jun 2025 09:45:04 +0000 Received: (at 78586) by debbugs.gnu.org; 4 Jun 2025 09:44:18 +0000 Received: from localhost ([127.0.0.1]:47284 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1uMkfR-00005D-VB for submit@debbugs.gnu.org; Wed, 04 Jun 2025 05:44:18 -0400 Received: from smtp1a.inetd.co.jp ([210.129.88.11]:37626) by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.84_2) (envelope-from ) id 1uMkfP-00004x-0H for 78586@debbugs.gnu.org; Wed, 04 Jun 2025 05:44:16 -0400 Received: from localhost (42-144-37-89.rev.home.ne.jp [42.144.37.89]) by smtp1a.inetd.co.jp (Postfix) with ESMTPSA id C3E8D5C; Wed, 4 Jun 2025 18:44:11 +0900 (JST) From: Ikumi Keita In-reply-to: References: Comments: In-reply-to "Paul D. Nelson" message dated "Tue, 03 Jun 2025 10:09:00 +0200." X-Mailer: MH-E 8.6+git; nmh 1.8; Emacs 30.1 MIME-Version: 1.0 Content-Type: text/plain; charset=iso-2022-jp Date: Wed, 04 Jun 2025 18:44:11 +0900 Message-ID: <6357.1749030251@localhost> X-Spam-Score: 0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Hi Paul, >>>>> "Paul D. Nelson" writes: > Deleting whitespace is relevant when converting from display to inline. > It seemed like the appropriate way to handle the variety of ways users > might write display math, e.g., $$ x + y $$ with or without newlines. I see, thanks for explanation. +(defun LaTeX--modify-math-1 (open close inline new-open new-close new-inline pos) + "Helper function for `LaTeX-modify-math'. +OPEN and CLOSE are the current delimiters, NEW-OPEN and NEW-CLOSE are +the new delimiters. INLINE and NEW-INLINE are booleans indicating +whether the current and new delimiters are inline or display math. +Assume point is at the start of the current OPEN delimiter. POS is a +marker that keeps track of cursor position." + (let ((converting-to-inline (and (not inline) new-inline))) + (when converting-to-inline + ;; Join with previous line if non-blank. + (when (save-excursion + (skip-chars-backward "[:blank:]") + (and + (bolp) (not (bobp)) + (progn + (forward-char -1) + (skip-chars-backward "[:blank:]") + (not (bolp))))) + (forward-char (length open)) + (save-excursion (join-line)) + (forward-char (- (length open))))) Why do you go forth and back here? What's wrong with a bare `join-line' without two `forward-char's? +(defun LaTeX-modify-math (new-type) + "Modify the current math construct to NEW-TYPE. + +Interactively, prompt for NEW-TYPE from a list of inline math +delimiters (\"$\", \"\\(\"), display math delimiters (\"$$\", +\"\\=\\[\") and valid LaTeX environments (\"equation\", ...). + +Non-interactively, NEW-TYPE must be either +- a string specifying the target delimiter or environment name, or +- a cons cell ((OPEN . CLOSE) . INLINE), where OPEN and CLOSE are + delimiters and INLINE is non-nil if the math construct is to be + understood as inline. + +The function converts the math construct at point (inline, display, or +environment) to the specified NEW-TYPE, preserving the content. If +point is not in a math construct, signal an error. Clears any active +previews at point before modification. + +Does not support modifying macro-based constructs such as \\ensuremath." + (interactive + (let* ((type (progn (texmathp) (car texmathp-why))) + (tbl (append '("$" "\\(" "$$" "\\[") + (LaTeX--math-environment-list)))) + (barf-if-buffer-read-only) + (unless type (user-error "Not inside math")) + (LaTeX--closing type) ;; Check for errors. + (list (completing-read + (format "Convert %s → " type) tbl nil t nil nil + type)))) + (let ((new-open (if (stringp new-type) + new-type + (caar new-type))) + (new-close (if (stringp new-type) + (LaTeX--closing new-type) + (cdar new-type))) + (new-inline (if (stringp new-type) + (member new-type '("$" "\\(")) + (cdr new-type)))) + (when (fboundp 'preview-clearout-at-point) + (preview-clearout-at-point)) + (unless (called-interactively-p 'any) + (unless (texmathp) (error "Not inside math"))) + (let ((type (car texmathp-why)) + (math-start (cdr texmathp-why)) + (pos (point-marker))) + (set-marker-insertion-type pos + (not + (and + (< (point) (point-max)) + (save-excursion + (forward-char) + (not (texmathp)))))) + (goto-char math-start) + (let* ((open (if (member type '("\\(" "$" "\\[" "$$")) + type + (concat TeX-esc "begin" TeX-grop type TeX-grcl))) + (close (LaTeX--closing type))) + (if (or (not (stringp new-type)) + (member new-open '("$" "\\(" "\\[" "$$"))) + ;; Conversion to inline or non-environment display. + (let* ((inline (member type '("$" "\\(")))) + (LaTeX--modify-math-1 open close inline new-open new-close new-inline pos)) + ;; Conversion to an environment. + (delete-char (length open)) + (push-mark (save-excursion + (search-forward close) + (delete-region (match-beginning 0) (match-end 0)) + (when (= (point) pos) + (set-marker pos nil)) We have to keep (setq pos nil) after `set-marker', which doesn't change the value of `pos' itself. + (when (member type '("$" "\\(")) + (skip-chars-forward ".,;:!?")) + (point))) + (activate-mark) + (LaTeX-insert-environment new-type))) + (when pos + (goto-char pos) + (set-marker pos nil))))) + +(defun LaTeX-make-inline () + "Convert LaTeX display math construct at point to inline math. +Remove the enclosing math construct (such as \\=\\[...\\=\\] or +\\begin{equation}...\\end{equation}) and replace it with inline math +surrounded by `TeX-electric-math' if non-nil, or \"$...$\", fitting the +result onto one line. Finally, leave any trailing punctuation outside +the math delimiters." + (interactive "*") + (LaTeX-modify-math + (if TeX-electric-math + (cons TeX-electric-math 'inline) + "$"))) As far as I can see, the proposed feature doesn't support docTeX mode. I don't think that is a practical problem at all, but addition of FIXME comment and breif mention about it in the documentation would be nice. Regards, Ikumi Keita #StandWithUkraine #StopWarInUkraine #Gaza #StopMassiveKilling #CeasefireNOW From unknown Sat Jun 14 19:44:59 2025 X-Loop: help-debbugs@gnu.org Subject: bug#78586: TeX-make-inline References: Resent-From: "Paul D. Nelson" Original-Sender: "Debbugs-submit" Resent-CC: bug-auctex@gnu.org Resent-Date: Wed, 04 Jun 2025 10:23:04 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 78586 X-GNU-PR-Package: auctex X-GNU-PR-Keywords: To: Ikumi Keita Cc: arash@gnu.org, 78586@debbugs.gnu.org Received: via spool by 78586-submit@debbugs.gnu.org id=B78586.174903255717784 (code B ref 78586); Wed, 04 Jun 2025 10:23:04 +0000 Received: (at 78586) by debbugs.gnu.org; 4 Jun 2025 10:22:37 +0000 Received: from localhost ([127.0.0.1]:47555 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1uMlGR-0004bl-As for submit@debbugs.gnu.org; Wed, 04 Jun 2025 06:22:36 -0400 Received: from mail-lf1-x131.google.com ([2a00:1450:4864:20::131]:52406) by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.84_2) (envelope-from ) id 1uMlGN-0004ad-NN for 78586@debbugs.gnu.org; Wed, 04 Jun 2025 06:22:29 -0400 Received: by mail-lf1-x131.google.com with SMTP id 2adb3069b0e04-55351af2fc6so2931778e87.0 for <78586@debbugs.gnu.org>; Wed, 04 Jun 2025 03:22:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1749032541; x=1749637341; darn=debbugs.gnu.org; h=mime-version:message-id:date:in-reply-to:subject:cc:to:from:from:to :cc:subject:date:message-id:reply-to; bh=lPYkio09ng0GqVtf//Kpeo8fCdH0lhd9E8TJf0thw5s=; b=ej0dUwQR/hJ6vaYXqemYNPQCmq5lu47LBx+qRpCwaChghh9B1GmUYEZPbse8gojWkY faKv8mfXEz6Bb5q6CWjolEGye/YpYH9fwXsqsNgnXpc+5iUMUr7D3RgIHn6HBI+OaQhD iQYqDGbtaRA9MPsR73buGDWYOglNMAiQSmVeTp6tzvzRFyG2ROGjhLjlikwp8XAKclVe 5Qupdh4EJuy9pkFFVqMJdGsLuSZrOkUyGtU6GdX39HUybSnVUvR+6Wa3zHYKBL2MSfwU mI9POeLSHhjzQ3jrp319b4JaPqwk9R9vrGJEyZlqUMXD7XFYelABVVDDhUklYzseSZTQ 1X9g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1749032541; x=1749637341; h=mime-version:message-id:date:in-reply-to:subject:cc:to:from :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=lPYkio09ng0GqVtf//Kpeo8fCdH0lhd9E8TJf0thw5s=; b=lo5FKEnYAr2jeznjpOHgwCSNpgOHliZGP8yY22T4X0FTFkRSPEZ2BvweqfaMwT585R OHqg/GgoTjCFcN4v3Z6Bfb9p9rw5nMxSdTRZRoIIuouY4kM9pDimn2MKkjqa3D3DI3b6 t0MDH1TcX588C5BFTfZBdPIvVbJa6l4XbimlcK+UNA08+Xk+OvOirsE20sCAWmbAcb4S 6yLZJDkAy88E8epYK7Bdzk/uXZTfMaYQs0Sabn03Bk6w+pDYfO1iOpXfgqtU438Kfyqt fVCAJbPpR3BTp95ZYQjjbqujTTKSr0um7JiSLJYQGUckJi0HOFpgKgKR3YIm2Pv6eNKg mGew== X-Forwarded-Encrypted: i=1; AJvYcCWLDgumRl/a47Dc7GhRYQvi2PkaVnKHXf/xt6Mi6Cbp5zn37V2FqmSt2e/EIP01YCvndFTgEQ==@debbugs.gnu.org X-Gm-Message-State: AOJu0YyGubwZWhebnk5gmQjCxW+zmw4xigQuyzxb2ZQ7VkJ55ObjDocc n6xCjrA6S68KnIVQBQy4PVvY5P/GUSIfWkIOETR6PP7UsJD8pB3g5N4Mwrhg8QvJBZc= X-Gm-Gg: ASbGncvWh7dQiSWSwqsPb/9iyiOwbn7OQi6zyVRUoaGMJLWnnbfp8zBveaMz06sU9jY jTeFJHBiODS7vY42JfsoJgseNTEqw1P196yima2xes+roU4GUNS/FPROKLgIB+RGWctKuoYVaBG S/4QXd+OrPbCWuJvilhrYvh1Ae6l3kuYCnuQQ2lXOS9e3CY+J/sbEsMD9D3BI+KmIiEJEknqOVv 96iRBT2zEPzBGdVesPdkYmvXVlQim5aAQVgS78VoWgHU8GiHJ6v29sLgquS0sjBCw0EjrCehQZr 3EUoydODH1Mg5cGo4pEMn9qs0OXEtb3xSDI1W+erOAFVgScl/pbYK5FT1+HMVOqAXFPUOABWslg XeEmHIAcaY7CTaMuIn7Q= X-Google-Smtp-Source: AGHT+IFKA0Nvvc6XLvJC72QtzwVTAtQP0TlDeSkgJx0b/dQ1ph/3mI6oDTaFcSsahl4sv4Fo5uqSIQ== X-Received: by 2002:a05:6512:3b24:b0:553:3073:c38b with SMTP id 2adb3069b0e04-55356af6f34mr613702e87.1.1749032540489; Wed, 04 Jun 2025 03:22:20 -0700 (PDT) Received: from localhost (wlan-eduroam-130-237-240-154.su.se. [130.237.240.154]) by smtp.gmail.com with UTF8SMTPSA id 2adb3069b0e04-5533791cc77sm2248692e87.165.2025.06.04.03.22.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 04 Jun 2025 03:22:19 -0700 (PDT) From: "Paul D. Nelson" In-Reply-To: <6357.1749030251@localhost> (message from Ikumi Keita on Wed, 04 Jun 2025 18:44:11 +0900) Date: Wed, 04 Jun 2025 12:22:19 +0200 Message-ID: MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Spam-Score: 0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain Hi Ikumi, > + (forward-char (length open)) > + (save-excursion (join-line)) > + (forward-char (- (length open))))) > > Why do you go forth and back here? What's wrong with a bare `join-line' > without two `forward-char's? Suppose the buffer contains: --8<---------------cut here---------------start------------->8--- We have \begin{equation*} x + y = z. \end{equation*} --8<---------------cut here---------------end--------------->8--- With point on line 2, join-line yields a buffer with first line: --8<---------------cut here---------------start------------->8--- We have \begin{equation*} --8<---------------cut here---------------end--------------->8--- The motivation for the slightly convoluted code is that, when point is at beginning of line, (save-excursion (join-line)) places point just before " \begin" (rather than just before "\begin", as one might have expected). On the other hand, it behaves in the expected way if point occurs later in the line (e.g., after "}"). Rather than trying to understand exactly why join-line behaves this way (which seems like a potentially non-robust feature that could change in the future), it seemed simpler just to do the little dance that you see in the code. I've added a comment to the code summarizing the above. > We have to keep > (setq pos nil) > after `set-marker', which doesn't change the value of `pos' itself. Thanks, good catch. > As far as I can see, the proposed feature doesn't support docTeX mode. I > don't think that is a practical problem at all, but addition of FIXME > comment and breif mention about it in the documentation would be nice. I'll trust you on this one -- I'm regrettably ignorant of TeX outside a limited practical subset of LaTeX. I've added some FIXME comments, hopefully as intended. There remains the question of where in the manual to document LaTeX-modify-math and whether to illustrate it via examples like in my earlier email. Thanks, best, Paul --=-=-= Content-Type: text/x-patch; charset=utf-8 Content-Disposition: attachment; filename=0001-Add-LaTeX-modify-math-and-LaTeX-make-inline.patch Content-Transfer-Encoding: quoted-printable >From af62d287b5f45fedbc963ad4231ef736045b38b4 Mon Sep 17 00:00:00 2001 From: Paul Nelson Date: Thu, 29 May 2025 11:14:11 +0200 Subject: [PATCH] Add LaTeX-modify-math and LaTeX-make-inline * latex.el (LaTeX--strip-labels, LaTeX--modify-math-1) (LaTeX--closing, LaTeX--math-environment-list): New helper functions. (LaTeX-modify-math, LaTeX-make-inline): New commands. * tests/latex/latex-modify-math-test.el: New test file. (latex-make-inline-test--with-temp-buffer): New test macro. (LaTeX-modify-math-inline-bracket-period) (LaTeX-modify-math-inline-double-dollar) (LaTeX-modify-math-inline-electric-math) (LaTeX-modify-math-inline-equation-env) (LaTeX-modify-math-inline-noop) (LaTeX-modify-math-inline-paren-to-dollar) (LaTeX-modify-math-inline-multiline-equation) (LaTeX-modify-math-inline-punctuation-semicolon) (LaTeX-modify-math-inline-multiple-punctuation) (LaTeX-modify-math-inline-whitespace-preservation) (LaTeX-modify-math-inline-empty-lines) (LaTeX-modify-math-dollar-to-bracket) (LaTeX-modify-math-paren-to-double-dollar) (LaTeX-modify-math-bracket-to-equation) (LaTeX-modify-math-point-inline-to-display-after-content) (LaTeX-modify-math-point-inline-to-display-before-content) (LaTeX-modify-math-point-display-to-inline-after-content) (LaTeX-modify-math-point-display-to-inline-before-content) (LaTeX-modify-math-point-multiline-roundtrip): New test cases. * doc/auctex.texi (Quotes): Document LaTeX-make-inline. --- doc/auctex.texi | 11 ++ latex.el | 207 ++++++++++++++++++++++++++ tests/latex/latex-modify-math-test.el | 203 +++++++++++++++++++++++++ 3 files changed, 421 insertions(+) create mode 100644 tests/latex/latex-modify-math-test.el diff --git a/doc/auctex.texi b/doc/auctex.texi index 0b486c8c..d62f83b7 100644 --- a/doc/auctex.texi +++ b/doc/auctex.texi @@ -484,6 +484,17 @@ to prevent unmatched dollar. Note that Texinfo mode does nothing special for @kbd{$}. It inserts dollar sign(s) just in the same way as the other normal keys do. =20 +@AUCTeX{} provides the command @code{LaTeX-make-inline} which converts the +display math environment at point to inline math. + +@deffn Command LaTeX-make-inline +Convert @LaTeX{} display math environment at point to inline math. This +command replaces the enclosing math environment such as @samp{\[...\]} or +@samp{\begin@{equation@}...\end@{equation@}} with the value of +@code{TeX-electric-math} or @samp{$...$} by default. (It may not work +correctly in docTeX.) +@end deffn + @subheading Braces =20 To avoid unbalanced braces, it is useful to insert them pairwise. You diff --git a/latex.el b/latex.el index 797513f2..29ddb9a8 100644 --- a/latex.el +++ b/latex.el @@ -9551,6 +9551,213 @@ no caption key is found, an error is issued. See a= lso the docstring of "LARGE" "huge" "Huge") "List of LaTeX font size declarations.") =20 +(defun LaTeX--strip-labels () + "Remove label commands between point and end of buffer." + (let ((re (concat + "\\(?:" + (if (bound-and-true-p reftex-label-regexps) + (mapconcat #'identity reftex-label-regexps "\\|") + (format "%slabel%s%s%s" + (regexp-quote TeX-esc) + TeX-grop "[^}]*" TeX-grcl)) + "\\)"))) + (save-excursion + (while (re-search-forward re nil t) + (replace-match ""))))) + +(defun LaTeX--modify-math-1 (open close inline new-open new-close new-inli= ne pos) + "Helper function for `LaTeX-modify-math'. +OPEN and CLOSE are the current delimiters, NEW-OPEN and NEW-CLOSE are +the new delimiters. INLINE and NEW-INLINE are booleans indicating +whether the current and new delimiters are inline or display math. +Assume point is at the start of the current OPEN delimiter. POS is a +marker that keeps track of cursor position." + (let ((converting-to-inline (and (not inline) new-inline))) + (when converting-to-inline + ;; Join with previous line if non-blank. + (when (save-excursion + (skip-chars-backward "[:blank:]") + (and + (bolp) (not (bobp)) + (progn + (forward-char -1) + (skip-chars-backward "[:blank:]") + (not (bolp))))) + ;; The following dance gets around the slightly counterintuitive + ;; behavior of (save-excursion (join-line)) with point at bol. + (forward-char (length open)) + (save-excursion (join-line)) + (forward-char (- (length open))))) + (unless new-inline + ;; Ensure non-inline delimiters start on a blank line. + (unless (save-excursion + (skip-chars-backward "[:blank:]") + (and + (bolp) (not (bobp)))) + (delete-horizontal-space) + (insert "\n"))) + ;; Delete opening delimiter. + (delete-char (length open)) + (let ((start (point))) + (search-forward close) + (when converting-to-inline + ;; Join with next line if non-blank. + (when (and (looking-at-p "[[:blank:]]*\n") + (save-excursion + (forward-line 1) + (not (looking-at-p "^[[:blank:]]*$")))) + (join-line 'next))) + (unless new-inline + (unless (looking-at-p "[[:blank:]]*\n") + (save-excursion + (insert "\n")))) + ;; Delete closing delimiter. + (delete-char (- (length close))) + (save-restriction + (narrow-to-region start (point)) + ;; Clear labels. + (goto-char (point-min)) + (LaTeX--strip-labels) + ;; Delete leading and trailing whitespace. + (dolist (re '("\\`[ \t\n\r]+" "[ \t\n\r]+\\'")) + (goto-char (point-min)) + (when (re-search-forward re nil t) + (replace-match ""))) + (unless new-inline + (goto-char (point-min)) + (insert "\n") + (goto-char (point-max)) + (insert "\n")) + ;; Insert new opening delimiter. + (goto-char (point-min)) + (insert new-open) + ;; Insert new closing delimiter + (goto-char (point-max)) + (when (=3D (point) pos) + (set-marker-insertion-type pos (not 'advance))) + (when converting-to-inline + (skip-chars-backward ".,;:!?")) + (insert new-close) + ;; Indent, including one line past the modified region. + (widen) + (end-of-line 2) + (indent-region start (point)))))) + +(defun LaTeX--math-environment-list () + "Return list of defined math environments. +This combines the env-on entries from `texmathp' and any user additions." + (texmathp-compile) + (mapcar #'car + (cl-remove-if-not + (lambda (entry) + (eq (nth 1 entry) 'env-on)) + texmathp-tex-commands1))) + +(defun LaTeX--closing (type) + "Return closing delimiter corresponding to given `texmathp' TYPE. +TYPE must be one of the (La)TeX symbols $, $$, \\( or \\=3D\\[, or a valid +environment name. Macros such as \\ensuremath are not supported." + (pcase type + ((or "$" "$$") type) + ("\\[" "\\]") + ("\\(" "\\)") + (_ (unless (member type (LaTeX--math-environment-list)) + (error "Invalid or unsupported opening delimiter: %s" type)) + (concat TeX-esc "end" TeX-grop type TeX-grcl)))) + +(defun LaTeX-modify-math (new-type) + "Modify the current math construct to NEW-TYPE. + +Interactively, prompt for NEW-TYPE from a list of inline math +delimiters (\"$\", \"\\(\"), display math delimiters (\"$$\", +\"\\=3D\\[\") and valid LaTeX environments (\"equation\", ...). + +Non-interactively, NEW-TYPE must be either +- a string specifying the target delimiter or environment name, or +- a cons cell ((OPEN . CLOSE) . INLINE), where OPEN and CLOSE are + delimiters and INLINE is non-nil if the math construct is to be + understood as inline. + +The function converts the math construct at point (inline, display, or +environment) to the specified NEW-TYPE, preserving the content. If +point is not in a math construct, signal an error. Clears any active +previews at point before modification. + +Does not support modifying macro-based constructs such as \\ensuremath." + ;; FIXME: this function may not work correctly in docTeX + (interactive + (let* ((type (progn (texmathp) (car texmathp-why))) + (tbl (append '("$" "\\(" "$$" "\\[") + (LaTeX--math-environment-list)))) + (barf-if-buffer-read-only) + (unless type (user-error "Not inside math")) + (LaTeX--closing type) ;; Check for errors. + (list (completing-read + (format "Convert %s =E2=86=92 " type) tbl nil t nil nil + type)))) + (let ((new-open (if (stringp new-type) + new-type + (caar new-type))) + (new-close (if (stringp new-type) + (LaTeX--closing new-type) + (cdar new-type))) + (new-inline (if (stringp new-type) + (member new-type '("$" "\\(")) + (cdr new-type)))) + (when (fboundp 'preview-clearout-at-point) + (preview-clearout-at-point)) + (unless (called-interactively-p 'any) + (unless (texmathp) (error "Not inside math"))) + (let ((type (car texmathp-why)) + (math-start (cdr texmathp-why)) + (pos (point-marker))) + (set-marker-insertion-type pos + (not + (and + (< (point) (point-max)) + (save-excursion + (forward-char) + (not (texmathp)))))) + (goto-char math-start) + (let* ((open (if (member type '("\\(" "$" "\\[" "$$")) + type + (concat TeX-esc "begin" TeX-grop type TeX-grcl))) + (close (LaTeX--closing type))) + (if (or (not (stringp new-type)) + (member new-open '("$" "\\(" "\\[" "$$"))) + ;; Conversion to inline or non-environment display. + (let* ((inline (member type '("$" "\\(")))) + (LaTeX--modify-math-1 open close inline new-open new-close n= ew-inline pos)) + ;; Conversion to an environment. + (delete-char (length open)) + (push-mark (save-excursion + (search-forward close) + (delete-region (match-beginning 0) (match-end 0)) + (when (=3D (point) pos) + (set-marker pos nil) + (setq pos nil)) + (when (member type '("$" "\\(")) + (skip-chars-forward ".,;:!?")) + (point))) + (activate-mark) + (LaTeX-insert-environment new-type))) + (when pos + (goto-char pos) + (set-marker pos nil))))) + +(defun LaTeX-make-inline () + "Convert LaTeX display math construct at point to inline math. +Remove the enclosing math construct (such as \\=3D\\[...\\=3D\\] or +\\begin{equation}...\\end{equation}) and replace it with inline math +surrounded by `TeX-electric-math' if non-nil, or \"$...$\". Leave any +trailing punctuation outside the math delimiters." + ;; FIXME: this function may not work correctly in docTeX + (interactive "*") + (LaTeX-modify-math + (if TeX-electric-math + (cons TeX-electric-math 'inline) + "$"))) + (provide 'latex) =20 ;;; latex.el ends here diff --git a/tests/latex/latex-modify-math-test.el b/tests/latex/latex-modi= fy-math-test.el new file mode 100644 index 00000000..f50d9ae3 --- /dev/null +++ b/tests/latex/latex-modify-math-test.el @@ -0,0 +1,203 @@ +;;; latex-modify-math-test.el --- tests for LaTeX-make-inline -*- lexical= -binding: t; -*- + +;; Copyright (C) 2025 Free Software Foundation, Inc. + +;; This file is part of AUCTeX. + +;; AUCTeX is free software; you can redistribute it and/or modify it +;; under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. + +;; AUCTeX is distributed in the hope that it will be useful, but +;; WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with AUCTeX; see the file COPYING. If not, write to the Free +;; Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +;; 02110-1301, USA. + +;;; Code: + +(require 'ert) +(require 'cl-lib) +(require 'latex) + +(defmacro latex-modify-test--with-temp-buffer (contents &rest body) + "Create a temporary LaTeX buffer with CONTENTS and execute BODY. +This macro is used to set up a test environment for `LaTeX-modify-math'." + (declare (indent 1) (debug t)) + `(with-temp-buffer + (LaTeX-mode) + (insert ,contents) + (goto-char (point-min)) + (cl-letf (((symbol-function 'preview-clearout-at-point) #'ignore)) + ,@body))) + +(ert-deftest LaTeX-modify-math-inline-bracket-period () + "Convert \\=3D\\[...\\=3D\\] to $..$ and keep trailing period." + (latex-modify-test--with-temp-buffer + "We have\n\\[ a+b =3D c. \\]" + (search-forward "b") + (LaTeX-make-inline) + (should (equal (buffer-string) "We have $a+b =3D c$.")))) + +(ert-deftest LaTeX-modify-math-inline-double-dollar () + "Convert $$..$$ to $..$." + (latex-modify-test--with-temp-buffer + "$$x!$$" + (search-forward "x") + (LaTeX-make-inline) + (should (equal (buffer-string) "$x$!")))) + +(ert-deftest LaTeX-modify-math-inline-electric-math () + "Respect `TeX-electric-math'." + (let ((TeX-electric-math '("\\(" . "\\)"))) + (latex-modify-test--with-temp-buffer + "\\[ x \\]" + (search-forward "x") + (LaTeX-make-inline) + (should (equal (buffer-string) "\\(x\\)"))))) + +(ert-deftest LaTeX-modify-math-inline-equation-env () + "Convert equation environment, drop \\label, keep comma." + (latex-modify-test--with-temp-buffer + "Hi.\n\nWe have\n\\begin{equation}\n\\label{l}x+y,\n\\end{equation}\= n" + (search-forward "x") + (let ((TeX-electric-math '("\\(" . "\\)"))) + (LaTeX-make-inline) + (should (equal (buffer-string) "Hi.\n\nWe have \\(x+y\\),\n"))))) + +(ert-deftest LaTeX-modify-math-inline-noop () + "Call inside inline math leaves buffer unchanged." + (latex-modify-test--with-temp-buffer + "Already $z$ inline." + (search-forward "z") + (LaTeX-make-inline) + (should (equal (buffer-string) "Already $z$ inline.")))) + +(ert-deftest LaTeX-modify-math-inline-paren-to-dollar () + "Convert \\(...\\) to $...$." + (latex-modify-test--with-temp-buffer + "Text \\(a + b\\) more text." + (search-forward "a") + (let ((TeX-electric-math nil)) + (LaTeX-make-inline) + (should (equal (buffer-string) "Text $a + b$ more text."))))) + +(ert-deftest LaTeX-modify-math-inline-multiline-equation () + "Convert multiline equation environment to inline, removing labels." + (latex-modify-test--with-temp-buffer + "Before\n\\begin{equation}\n x + y =3D z\n \\label{eq:test}\n\\end= {equation}\nAfter" + (search-forward "x") + (LaTeX-make-inline) + (should (equal (buffer-string) "Before $x + y =3D z$ After")))) + +(ert-deftest LaTeX-modify-math-inline-punctuation-semicolon () + "Move semicolon outside inline math." + (latex-modify-test--with-temp-buffer + "\\[ x + y; \\]" + (search-forward "x") + (LaTeX-make-inline) + (should (equal (buffer-string) "$x + y$;")))) + +(ert-deftest LaTeX-modify-math-inline-multiple-punctuation () + "Handle multiple punctuation marks." + (latex-modify-test--with-temp-buffer + "\\[ result?! \\]" + (search-forward "result") + (LaTeX-make-inline) + (should (equal (buffer-string) "$result$?!")))) + +(ert-deftest LaTeX-modify-math-inline-whitespace-preservation () + "Preserve surrounding whitespace appropriately." + (latex-modify-test--with-temp-buffer + "Text \\[ a + b \\] more." + (search-forward "a") + (LaTeX-make-inline) + (should (equal (buffer-string) "Text $a + b$ more.")))) + +(ert-deftest LaTeX-modify-math-inline-empty-lines () + "Remove empty lines from display math when converting." + (latex-modify-test--with-temp-buffer + "\\[\n\n x =3D y \n\n\\]" + (search-forward "x") + (LaTeX-make-inline) + (should (equal (buffer-string) "$x =3D y$")))) + +(ert-deftest LaTeX-modify-math-dollar-to-bracket () + "Convert $...$ to \\=3D\\[...\\=3D\\]." + (latex-modify-test--with-temp-buffer + "Text $x + y$ more." + (search-forward "+") + (LaTeX-modify-math "\\[") + (should (equal (buffer-string) "Text\n\\[\n x + y\n\\]\nmore.")))) + +(ert-deftest LaTeX-modify-math-paren-to-double-dollar () + "Convert \\(...\\) to $$...$$." + (latex-modify-test--with-temp-buffer + "Text \\(a =3D b\\) end." + (search-forward "a") + (LaTeX-modify-math "$$") + (should (equal (buffer-string) "Text\n$$\na =3D b\n$$\nend.")))) + +(ert-deftest LaTeX-modify-math-bracket-to-equation () + "Convert \\=3D\\[...\\=3D\\] to equation environment." + (latex-modify-test--with-temp-buffer + "\\[ f(x) =3D x^2 \\]" + (search-forward "f") + (LaTeX-modify-math "equation") + (should (equal (buffer-string) "\\begin{equation}\n f(x) =3D x^2\n\\e= nd{equation}")))) + +(ert-deftest LaTeX-modify-math-point-inline-to-display-after-content () + "Point after inline content preserved after display conversion." + (latex-modify-test--with-temp-buffer + "A $x+y$ B" + (search-forward "y") + (LaTeX-modify-math "\\[") + (should (looking-back "y" (1- (point)))) + (should (looking-at "\n[[:space:]]*\\\\\\]")))) + +(ert-deftest LaTeX-modify-math-point-inline-to-display-before-content () + "Point before inline content preserved after display conversion." + (latex-modify-test--with-temp-buffer + "A $x+y$ B" + (search-forward "$") + (LaTeX-modify-math "\\[") + (looking-at "x") + (should (looking-at "x")))) + +(ert-deftest LaTeX-modify-math-point-display-to-inline-after-content () + "Point after display content preserved after inline conversion." + (latex-modify-test--with-temp-buffer + "\\[\n x + y\n\\]" + (goto-char (point-min)) + (re-search-forward "y") + (LaTeX-make-inline) + (should (looking-back "y" (1- (point)))) + (should (looking-at "\\$")))) + +(ert-deftest LaTeX-modify-math-point-display-to-inline-before-content () + "Point before display content preserved after inline conversion." + (latex-modify-test--with-temp-buffer + "\\[\n x + y\n\\]" + (goto-char (point-min)) + (re-search-forward "x") + (forward-char -1) + (LaTeX-make-inline) + (should (looking-at "x")))) + +(ert-deftest LaTeX-modify-math-point-multiline-roundtrip () + "Point before/after content preserved for round-trip conversion." + (latex-modify-test--with-temp-buffer + "foo $x+y$ bar" + (search-forward "y") + (backward-char) + (LaTeX-modify-math "\\[") + (should (looking-at "y")) + (LaTeX-make-inline) + (should (looking-at "y")))) + +;;; latex-modify-math-test.el ends here --=20 2.39.3 (Apple Git-145) --=-=-=-- From unknown Sat Jun 14 19:44:59 2025 X-Loop: help-debbugs@gnu.org Subject: bug#78586: TeX-make-inline Resent-From: Ikumi Keita Original-Sender: "Debbugs-submit" Resent-CC: bug-auctex@gnu.org Resent-Date: Thu, 05 Jun 2025 14:53:08 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 78586 X-GNU-PR-Package: auctex X-GNU-PR-Keywords: To: "Paul D. Nelson" Cc: arash@gnu.org, 78586@debbugs.gnu.org Received: via spool by 78586-submit@debbugs.gnu.org id=B78586.174913513131392 (code B ref 78586); Thu, 05 Jun 2025 14:53:08 +0000 Received: (at 78586) by debbugs.gnu.org; 5 Jun 2025 14:52:11 +0000 Received: from localhost ([127.0.0.1]:35140 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1uNBws-00089l-7A for submit@debbugs.gnu.org; Thu, 05 Jun 2025 10:52:09 -0400 Received: from smtp1a.inetd.co.jp ([210.129.88.11]:40700) by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.84_2) (envelope-from ) id 1uNBwX-00087j-TT for 78586@debbugs.gnu.org; Thu, 05 Jun 2025 10:51:59 -0400 Received: from localhost (42-144-37-89.rev.home.ne.jp [42.144.37.89]) by smtp1a.inetd.co.jp (Postfix) with ESMTPSA id B8ADB5C; Thu, 5 Jun 2025 23:51:42 +0900 (JST) From: Ikumi Keita In-reply-to: References: Comments: In-reply-to "Paul D. Nelson" message dated "Wed, 04 Jun 2025 12:22:19 +0200." X-Mailer: MH-E 8.6+git; nmh 1.8; Emacs 30.1 MIME-Version: 1.0 Content-Type: text/plain; charset=iso-2022-jp Date: Thu, 05 Jun 2025 23:51:42 +0900 Message-ID: <9810.1749135102@localhost> X-Spam-Score: 0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Hi Paul, >>>>> "Paul D. Nelson" writes: > Suppose the buffer contains: > We have > \begin{equation*} > x + y = z. > \end{equation*} > With point on line 2, join-line yields a buffer with first line: > We have \begin{equation*} > The motivation for the slightly convoluted code is that, when point is > at beginning of line, (save-excursion (join-line)) places point just > before " \begin" (rather than just before "\begin", as one might have > expected). Thanks for explanation. Hmm, it's indeed annoying. :-( > I'll trust you on this one -- I'm regrettably ignorant of TeX outside a > limited practical subset of LaTeX. To have a minimum acquaintance with docTeX document, visit latex/preview.dtx in AUCTeX repository. It's basically full of "commented" text with leading "%" sign at the beginning of line. > I've added some FIXME comments, hopefully as intended. Thank you, those are enough. +(defun LaTeX-modify-math (new-type) + "Modify the current math construct to NEW-TYPE. + +Interactively, prompt for NEW-TYPE from a list of inline math +delimiters (\"$\", \"\\(\"), display math delimiters (\"$$\", +\"\\=\\[\") and valid LaTeX environments (\"equation\", ...). + +Non-interactively, NEW-TYPE must be either +- a string specifying the target delimiter or environment name, or +- a cons cell ((OPEN . CLOSE) . INLINE), where OPEN and CLOSE are + delimiters and INLINE is non-nil if the math construct is to be + understood as inline. + +The function converts the math construct at point (inline, display, or +environment) to the specified NEW-TYPE, preserving the content. If +point is not in a math construct, signal an error. Clears any active +previews at point before modification. + +Does not support modifying macro-based constructs such as \\ensuremath." + ;; FIXME: this function may not work correctly in docTeX + (interactive + (let* ((type (progn (texmathp) (car texmathp-why))) + (tbl (append '("$" "\\(" "$$" "\\[") + (LaTeX--math-environment-list)))) It seems `let' is enough. (I don't know the C implementation of `let' and `let*' of elisp; maybe is there any guideline which recommends `let*' over `let', due to the implementation detail, when both can do the job equally?) + (barf-if-buffer-read-only) + (unless type (user-error "Not inside math")) + (LaTeX--closing type) ;; Check for errors. + (list (completing-read + (format "Convert %s → " type) tbl nil t nil nil + type)))) + (let ((new-open (if (stringp new-type) + new-type + (caar new-type))) + (new-close (if (stringp new-type) + (LaTeX--closing new-type) + (cdar new-type))) + (new-inline (if (stringp new-type) + (member new-type '("$" "\\(")) + (cdr new-type)))) + (when (fboundp 'preview-clearout-at-point) + (preview-clearout-at-point)) + (unless (called-interactively-p 'any) + (unless (texmathp) (error "Not inside math"))) + (let ((type (car texmathp-why)) + (math-start (cdr texmathp-why)) + (pos (point-marker))) + (set-marker-insertion-type pos + (not + (and + (< (point) (point-max)) + (save-excursion + (forward-char) + (not (texmathp)))))) + (goto-char math-start) + (let* ((open (if (member type '("\\(" "$" "\\[" "$$")) + type + (concat TeX-esc "begin" TeX-grop type TeX-grcl))) + (close (LaTeX--closing type))) Same comment with respect to `let' and `let*'. + (if (or (not (stringp new-type)) + (member new-open '("$" "\\(" "\\[" "$$"))) + ;; Conversion to inline or non-environment display. + (let* ((inline (member type '("$" "\\(")))) Same comment. > There remains the question of where in the manual to document > LaTeX-modify-math and whether to illustrate it via examples like in my > earlier email. AUCTeX manual already has "Mathematics" node, so I think you should add explanation there. Examples are welcomed in the manual. Users who don't know elisp well will know how to use the prepaired function. > (defun my-LaTeX-make-brackets () > "Convert math construct at point to \"\\=\\[..\\=\\]\"." ^^^ I'd suggest to remove quotation for \]. In contrast to \[, \] will be displayed literally without \=, though extra \= is harmless. Regards, Ikumi Keita #StandWithUkraine #StopWarInUkraine #Gaza #StopMassiveKilling #CeasefireNOW From unknown Sat Jun 14 19:44:59 2025 X-Loop: help-debbugs@gnu.org Subject: bug#78586: TeX-make-inline References: Resent-From: "Paul D. Nelson" Original-Sender: "Debbugs-submit" Resent-CC: bug-auctex@gnu.org Resent-Date: Sun, 08 Jun 2025 14:06:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 78586 X-GNU-PR-Package: auctex X-GNU-PR-Keywords: To: Ikumi Keita Cc: arash@gnu.org, 78586@debbugs.gnu.org Received: via spool by 78586-submit@debbugs.gnu.org id=B78586.174939153411326 (code B ref 78586); Sun, 08 Jun 2025 14:06:01 +0000 Received: (at 78586) by debbugs.gnu.org; 8 Jun 2025 14:05:34 +0000 Received: from localhost ([127.0.0.1]:52446 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1uOGeS-0002wa-Jn for submit@debbugs.gnu.org; Sun, 08 Jun 2025 10:05:34 -0400 Received: from mail-lf1-x131.google.com ([2a00:1450:4864:20::131]:57507) by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.84_2) (envelope-from ) id 1uOGeP-0002tH-Kb for 78586@debbugs.gnu.org; Sun, 08 Jun 2025 10:05:31 -0400 Received: by mail-lf1-x131.google.com with SMTP id 2adb3069b0e04-5533303070cso3887309e87.2 for <78586@debbugs.gnu.org>; Sun, 08 Jun 2025 07:05:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1749391523; x=1749996323; darn=debbugs.gnu.org; h=mime-version:message-id:date:in-reply-to:subject:cc:to:from:from:to :cc:subject:date:message-id:reply-to; bh=2IXekL9UKk3r4vcVDSC8tHnltPI7SzSk9JA8a+0W7wc=; b=Jjh3L3jHyga2r17b60NgV8CQi0M1kZ9+4shT+pXNR7m59HkffRX+9cwUvceS6+Ys4z 9H9cbtLaFN6mvQytzqyeiu1FIS7ZCckxf5vAMPVbJYRo6Qr5FGG73rmGC6v9KzyCcw71 E/CoiB7m+TrTqVaGpQhLn6LRJ2Vt509DAK8pKsGhw7cULz0CLSIG3XOb7eQc4SMLI/SS uhd5SjlmWAcw24f7qLNmxMnBlNGyYfZAqCau72gzroDXru6UN69P/XATt8mROkMles1K /5lfIRYhymNmvf3lTPmIXZx+bSg4NutmyfY7Dw33SrtsIieHU5bwry1FoTKKl0MuqZ/2 CTjQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1749391523; x=1749996323; h=mime-version:message-id:date:in-reply-to:subject:cc:to:from :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=2IXekL9UKk3r4vcVDSC8tHnltPI7SzSk9JA8a+0W7wc=; b=uTOpKaB31zeP4iZOyz2TDTEiEgCauewJqKEvGLE5qYR5kxJpo07N/yAUcz75aM+nWI 0z4eyznmHO2BKgMCyHli1U7STrZf4WiVmaiBCEfksYvK7BIJvRAvYMhciUNWb/fDI6sd CcWmW2VZHvZ5U3W22NHs53tSi5ARMITmqqS6+W9FMJ9M+dGq0vQc/jzEiV92efX4exOJ IdTgyUB/vA4GZuKN+bNAUZDyLDRBNCI57/T4VGr/LEtMy1tKf+E6z1KJcxdfQZEEW+p1 U43vwlMjgpuIcp6Gekzqc1BAPOjGsN2MRgWpLbskTTAwLb8xveCjXwAVAZKZikTPBdYX nbQA== X-Forwarded-Encrypted: i=1; AJvYcCU+dW6P8QgjRuFIvz2hTKgVnejtgX6I/snTi64jtSUn6V1wRY4ZJlXUFfWOSjIUQEUzmXbkGw==@debbugs.gnu.org X-Gm-Message-State: AOJu0YxDvaV1xTOoqUx6AxxwMG740R5AUggcghCaJVdUk37lemybNRc9 ZAbT7ZwSeposEAhhYf9tvSCETv0PkHnCHbtny0/C5bDnaSPTLH4E2Q/k X-Gm-Gg: ASbGncutQTOBSuPQSSl2TqHUBxP4ytIFeJtbhXEwoj8bBc+iYQ6lbkhadSyE2t8rbzj bWRSDZkIjK+jb0k8uf56+V194pm5BHCd906+cXPHx+xjz4Vi3ebDT+IN08oL8QkoVUFPO8tn3s9 sVFU6EV/ThKDvfR0v9sre4vtY0Ub+5tm30EfyPcloXunB2eT9+YeK5jCdEy2aepfqj79L2xE+c8 krf5dVNps4lssfopdXSxlZe3bqUgqq/P/wj7PP/fc8iApbiesqrla/vS0IMS906uy2SfRnIHXVa GT7/zJXBxTK8+f7Q2D5MAxzhuJO5U0bLCOhP+AZGZPL8AMUpx2T+M6xEZG/j1QqCmJY= X-Google-Smtp-Source: AGHT+IGA0xzigj91xQTW2wiUXBTmER8SQWd+Gfbcmr+5Cf7MclfDsM9bigFLA9d4po6z7jFFn8kh8g== X-Received: by 2002:a05:6512:ba9:b0:553:252f:addf with SMTP id 2adb3069b0e04-55366bd4109mr2644372e87.10.1749391522658; Sun, 08 Jun 2025 07:05:22 -0700 (PDT) Received: from localhost ([185.229.155.48]) by smtp.gmail.com with UTF8SMTPSA id 2adb3069b0e04-553676d0eeesm790024e87.47.2025.06.08.07.05.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 08 Jun 2025 07:05:21 -0700 (PDT) From: "Paul D. Nelson" In-Reply-To: <9810.1749135102@localhost> (message from Ikumi Keita on Thu, 05 Jun 2025 23:51:42 +0900) Date: Sun, 08 Jun 2025 16:05:19 +0200 Message-ID: MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Spam-Score: 0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain Hi Ikumi, I fixed the let/let* issues you noted. > AUCTeX manual already has "Mathematics" node, so I think you should add > explanation there. > Examples are welcomed in the manual. Users who don't know elisp well > will know how to use the prepaired function. I've updated the attached patch with docs (so I think it's now in good shape, but I always welcome feedback on my texinfo). >> (defun my-LaTeX-make-brackets () >> "Convert math construct at point to \"\\=\\[..\\=\\]\"." > ^^^ > I'd suggest to remove quotation for \]. In contrast to \[, \] will be > displayed literally without \=, though extra \= is harmless. Done. Any further feedback welcome! Paul --=-=-= Content-Type: text/x-patch; charset=utf-8 Content-Disposition: attachment; filename=0001-Add-LaTeX-modify-math-and-LaTeX-make-inline.patch Content-Transfer-Encoding: quoted-printable >From 13e311945503d0e89907504f256b8c0c747e42ca Mon Sep 17 00:00:00 2001 From: Paul Nelson Date: Thu, 29 May 2025 11:14:11 +0200 Subject: [PATCH] Add LaTeX-modify-math and LaTeX-make-inline * latex.el (LaTeX--strip-labels, LaTeX--modify-math-1) (LaTeX--closing, LaTeX--math-environment-list): New helper functions. (LaTeX-modify-math, LaTeX-make-inline): New commands (bug#78586). * tests/latex/latex-modify-math-test.el: New test file. (latex-make-inline-test--with-temp-buffer): New test macro. (LaTeX-modify-math-inline-bracket-period) (LaTeX-modify-math-inline-double-dollar) (LaTeX-modify-math-inline-electric-math) (LaTeX-modify-math-inline-equation-env) (LaTeX-modify-math-inline-noop) (LaTeX-modify-math-inline-paren-to-dollar) (LaTeX-modify-math-inline-multiline-equation) (LaTeX-modify-math-inline-punctuation-semicolon) (LaTeX-modify-math-inline-multiple-punctuation) (LaTeX-modify-math-inline-whitespace-preservation) (LaTeX-modify-math-inline-empty-lines) (LaTeX-modify-math-dollar-to-bracket) (LaTeX-modify-math-paren-to-double-dollar) (LaTeX-modify-math-bracket-to-equation) (LaTeX-modify-math-point-inline-to-display-after-content) (LaTeX-modify-math-point-inline-to-display-before-content) (LaTeX-modify-math-point-display-to-inline-after-content) (LaTeX-modify-math-point-display-to-inline-before-content) (LaTeX-modify-math-point-multiline-roundtrip): New test cases. * doc/auctex.texi (Quotes): Document LaTeX-make-inline. (Mathematics): Document LaTeX-modify-math and variants. --- doc/auctex.texi | 114 ++++++++++++++ latex.el | 207 ++++++++++++++++++++++++++ tests/latex/latex-modify-math-test.el | 203 +++++++++++++++++++++++++ 3 files changed, 524 insertions(+) create mode 100644 tests/latex/latex-modify-math-test.el diff --git a/doc/auctex.texi b/doc/auctex.texi index 0b486c8c..5629a693 100644 --- a/doc/auctex.texi +++ b/doc/auctex.texi @@ -484,6 +484,17 @@ to prevent unmatched dollar. Note that Texinfo mode does nothing special for @kbd{$}. It inserts dollar sign(s) just in the same way as the other normal keys do. =20 +@AUCTeX{} provides the command @code{LaTeX-make-inline} which converts the +display math environment at point to inline math. + +@deffn Command LaTeX-make-inline +Convert @LaTeX{} display math environment at point to inline math. This +command replaces the enclosing math environment such as @samp{\[...\]} or +@samp{\begin@{equation@}...\end@{equation@}} with the value of +@code{TeX-electric-math} or @samp{$...$} by default. (It may not work +correctly in docTeX.) +@end deffn + @subheading Braces =20 To avoid unbalanced braces, it is useful to insert them pairwise. You @@ -1290,6 +1301,109 @@ is typed to begin math mode or a math environment i= s inserted by @kbd{C-c C-e} (@code{LaTeX-environment}). @end defopt =20 +@subheading Modifying Math Delimiters and Environments +@cindex LaTeX-modify-math +@cindex Inline math, converting +@cindex Display math, converting +@cindex Math environment, converting + +@AUCTeX{} offers the command @code{LaTeX-modify-math} to convert the +mathematical construct at point---whether it is inline math such as +@samp{$...$} or @samp{\(...\)}, a display construct such as @samp{$$...$$} +or @samp{\[...\]}, or an environment such as @samp{\begin@{equation@} +... \end@{equation@}}---into a different kind of delimiter or environment. + +@deffn Command LaTeX-modify-math +Interactively, prompt for the target delimiter or environment. The +completion table contains the inline delimiters @samp{$} and @samp{\(}, +the display delimiters @samp{$$} and @samp{\[}, and every math environment +known to @code{texmathp}, such as @samp{equation}, @samp{align*}, or +anything in the user option @code{texmathp-tex-commands}. The current +construct is then rewritten using the chosen form, taking care to +@itemize @bullet +@item keep any trailing punctuation outside inline math, +@item put display constructs on their own lines, and +@item strip any @code{\label@{@}} commands when converting to inline math. +@end itemize + +When called from Lisp, @var{new-type} may be a string naming a delimiter +or environment, or a cons @code{((@var{open} . @var{close}) +. @var{inline})} specifying custom delimiters, where @var{inline} is +non-@code{nil} for inline math. + +This command does @emph{not} understand macro-based math wrappers such as +@code{\ensuremath}. It may also fail in docTeX buffers. +@end deffn + +A related command, invoked with a prefix argument, is @kbd{C-u C-c C-e} +(@code{LaTeX-environment}) (@pxref{Environments}). This modifies the +current @LaTeX{} environment, while @code{LaTeX-modify-math} also handles +inline/display constructs. + +You can define commands that convert to a particular form, e.g.@: by +adding the following to your init file:: + +@lisp +(defun my-LaTeX-make-brackets () + "Convert math construct at point to \"\\=3D\\[..\\]\"." + (interactive) + (LaTeX-modify-math "\\[")) +@end lisp + +@lisp +(defun my-LaTeX-make-equation* () + "Convert math construct at point to \"equation*\"." + (interactive) + (LaTeX-modify-math "equation*")) +@end lisp + +You can use @code{LaTeX-modify-math} to build higher=E2=80=91level toggles= . The +following modifies any math construct to an @samp{equation*} environment, +then toggles the numbered status: + +@lisp +(defun my-LaTeX-toggle-numbered () + "Convert math construct at point to \"equation*\". +If the math construct is already \"equation*\", then toggle with the +numbered variant \"equation\"." + (interactive) + (unless (texmathp) (user-error "Not inside math")) + (let ((current (car texmathp-why))) + (LaTeX-modify-math + (pcase current + ("equation*" "equation") + ("equation" "equation*") + (_ "equation*"))))) +@end lisp + +A further example toggles between @samp{equation}, @samp{align} and their +starred forms: + +@lisp +(defun my-LaTeX-toggle-align () + "Toggle math environment at point between \"equation\" and \"align\"." + (interactive) + (unless (texmathp) (user-error "Not inside math")) + (let ((current (car texmathp-why))) + (LaTeX-modify-math + (pcase current + ("align*" "equation*") + ("equation*" "align*") + ("align" "equation") + ("equation" "align") + (_ "align*"))))) +@end lisp + +Such helper commands can be bound in @code{LaTeX-mode-map} as you see fit, +e.g.@: by adding the following to your init file: + +@lisp +(keymap-set LaTeX-mode-map "C-c e" #'my-LaTeX-make-equation*) +@end lisp + +@xref{Quotes,,LaTeX-make-inline}, for a built-in convenience wrapper that +converts display constructs to inline math. + @node Completion @section Completion @cindex Completion diff --git a/latex.el b/latex.el index 797513f2..81da0c40 100644 --- a/latex.el +++ b/latex.el @@ -9551,6 +9551,213 @@ no caption key is found, an error is issued. See a= lso the docstring of "LARGE" "huge" "Huge") "List of LaTeX font size declarations.") =20 +(defun LaTeX--strip-labels () + "Remove label commands between point and end of buffer." + (let ((re (concat + "\\(?:" + (if (bound-and-true-p reftex-label-regexps) + (mapconcat #'identity reftex-label-regexps "\\|") + (format "%slabel%s%s%s" + (regexp-quote TeX-esc) + TeX-grop "[^}]*" TeX-grcl)) + "\\)"))) + (save-excursion + (while (re-search-forward re nil t) + (replace-match ""))))) + +(defun LaTeX--modify-math-1 (open close inline new-open new-close new-inli= ne pos) + "Helper function for `LaTeX-modify-math'. +OPEN and CLOSE are the current delimiters, NEW-OPEN and NEW-CLOSE are +the new delimiters. INLINE and NEW-INLINE are booleans indicating +whether the current and new delimiters are inline or display math. +Assume point is at the start of the current OPEN delimiter. POS is a +marker that keeps track of cursor position." + (let ((converting-to-inline (and (not inline) new-inline))) + (when converting-to-inline + ;; Join with previous line if non-blank. + (when (save-excursion + (skip-chars-backward "[:blank:]") + (and + (bolp) (not (bobp)) + (progn + (forward-char -1) + (skip-chars-backward "[:blank:]") + (not (bolp))))) + ;; The following dance gets around the slightly counterintuitive + ;; behavior of (save-excursion (join-line)) with point at bol. + (forward-char (length open)) + (save-excursion (join-line)) + (forward-char (- (length open))))) + (unless new-inline + ;; Ensure non-inline delimiters start on a blank line. + (unless (save-excursion + (skip-chars-backward "[:blank:]") + (and + (bolp) (not (bobp)))) + (delete-horizontal-space) + (insert "\n"))) + ;; Delete opening delimiter. + (delete-char (length open)) + (let ((start (point))) + (search-forward close) + (when converting-to-inline + ;; Join with next line if non-blank. + (when (and (looking-at-p "[[:blank:]]*\n") + (save-excursion + (forward-line 1) + (not (looking-at-p "^[[:blank:]]*$")))) + (join-line 'next))) + (unless new-inline + (unless (looking-at-p "[[:blank:]]*\n") + (save-excursion + (insert "\n")))) + ;; Delete closing delimiter. + (delete-char (- (length close))) + (save-restriction + (narrow-to-region start (point)) + ;; Clear labels. + (goto-char (point-min)) + (LaTeX--strip-labels) + ;; Delete leading and trailing whitespace. + (dolist (re '("\\`[ \t\n\r]+" "[ \t\n\r]+\\'")) + (goto-char (point-min)) + (when (re-search-forward re nil t) + (replace-match ""))) + (unless new-inline + (goto-char (point-min)) + (insert "\n") + (goto-char (point-max)) + (insert "\n")) + ;; Insert new opening delimiter. + (goto-char (point-min)) + (insert new-open) + ;; Insert new closing delimiter + (goto-char (point-max)) + (when (=3D (point) pos) + (set-marker-insertion-type pos (not 'advance))) + (when converting-to-inline + (skip-chars-backward ".,;:!?")) + (insert new-close) + ;; Indent, including one line past the modified region. + (widen) + (end-of-line 2) + (indent-region start (point)))))) + +(defun LaTeX--math-environment-list () + "Return list of defined math environments. +This combines the env-on entries from `texmathp' and any user additions." + (texmathp-compile) + (mapcar #'car + (cl-remove-if-not + (lambda (entry) + (eq (nth 1 entry) 'env-on)) + texmathp-tex-commands1))) + +(defun LaTeX--closing (type) + "Return closing delimiter corresponding to given `texmathp' TYPE. +TYPE must be one of the (La)TeX symbols $, $$, \\( or \\=3D\\[, or a valid +environment name. Macros such as \\ensuremath are not supported." + (pcase type + ((or "$" "$$") type) + ("\\[" "\\]") + ("\\(" "\\)") + (_ (unless (member type (LaTeX--math-environment-list)) + (error "Invalid or unsupported opening delimiter: %s" type)) + (concat TeX-esc "end" TeX-grop type TeX-grcl)))) + +(defun LaTeX-modify-math (new-type) + "Modify the current math construct to NEW-TYPE. + +Interactively, prompt for NEW-TYPE from a list of inline math +delimiters (\"$\", \"\\(\"), display math delimiters (\"$$\", +\"\\=3D\\[\") and valid LaTeX environments (\"equation\", ...). + +Non-interactively, NEW-TYPE must be either +- a string specifying the target delimiter or environment name, or +- a cons cell ((OPEN . CLOSE) . INLINE), where OPEN and CLOSE are + delimiters and INLINE is non-nil if the math construct is to be + understood as inline. + +The function converts the math construct at point (inline, display, or +environment) to the specified NEW-TYPE, preserving the content. If +point is not in a math construct, signal an error. Clears any active +previews at point before modification. + +Does not support modifying macro-based constructs such as \\ensuremath." + ;; FIXME: this function may not work correctly in docTeX + (interactive + (let ((type (progn (texmathp) (car texmathp-why))) + (tbl (append '("$" "\\(" "$$" "\\[") + (LaTeX--math-environment-list)))) + (barf-if-buffer-read-only) + (unless type (user-error "Not inside math")) + (LaTeX--closing type) ;; Check for errors. + (list (completing-read + (format "Convert %s =E2=86=92 " type) tbl nil t nil nil + type)))) + (let ((new-open (if (stringp new-type) + new-type + (caar new-type))) + (new-close (if (stringp new-type) + (LaTeX--closing new-type) + (cdar new-type))) + (new-inline (if (stringp new-type) + (member new-type '("$" "\\(")) + (cdr new-type)))) + (when (fboundp 'preview-clearout-at-point) + (preview-clearout-at-point)) + (unless (called-interactively-p 'any) + (unless (texmathp) (error "Not inside math"))) + (let ((type (car texmathp-why)) + (math-start (cdr texmathp-why)) + (pos (point-marker))) + (set-marker-insertion-type pos + (not + (and + (< (point) (point-max)) + (save-excursion + (forward-char) + (not (texmathp)))))) + (goto-char math-start) + (let ((open (if (member type '("\\(" "$" "\\[" "$$")) + type + (concat TeX-esc "begin" TeX-grop type TeX-grcl))) + (close (LaTeX--closing type))) + (if (or (not (stringp new-type)) + (member new-open '("$" "\\(" "\\[" "$$"))) + ;; Conversion to inline or non-environment display. + (let ((inline (member type '("$" "\\(")))) + (LaTeX--modify-math-1 open close inline new-open new-close n= ew-inline pos)) + ;; Conversion to an environment. + (delete-char (length open)) + (push-mark (save-excursion + (search-forward close) + (delete-region (match-beginning 0) (match-end 0)) + (when (=3D (point) pos) + (set-marker pos nil) + (setq pos nil)) + (when (member type '("$" "\\(")) + (skip-chars-forward ".,;:!?")) + (point))) + (activate-mark) + (LaTeX-insert-environment new-type))) + (when pos + (goto-char pos) + (set-marker pos nil))))) + +(defun LaTeX-make-inline () + "Convert LaTeX display math construct at point to inline math. +Remove the enclosing math construct (such as \\=3D\\[...\\] or +\\begin{equation}...\\end{equation}) and replace it with inline math +surrounded by `TeX-electric-math' if non-nil, or \"$...$\". Leave any +trailing punctuation outside the math delimiters." + ;; FIXME: this function may not work correctly in docTeX + (interactive "*") + (LaTeX-modify-math + (if TeX-electric-math + (cons TeX-electric-math 'inline) + "$"))) + (provide 'latex) =20 ;;; latex.el ends here diff --git a/tests/latex/latex-modify-math-test.el b/tests/latex/latex-modi= fy-math-test.el new file mode 100644 index 00000000..f50d9ae3 --- /dev/null +++ b/tests/latex/latex-modify-math-test.el @@ -0,0 +1,203 @@ +;;; latex-modify-math-test.el --- tests for LaTeX-make-inline -*- lexical= -binding: t; -*- + +;; Copyright (C) 2025 Free Software Foundation, Inc. + +;; This file is part of AUCTeX. + +;; AUCTeX is free software; you can redistribute it and/or modify it +;; under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. + +;; AUCTeX is distributed in the hope that it will be useful, but +;; WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with AUCTeX; see the file COPYING. If not, write to the Free +;; Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +;; 02110-1301, USA. + +;;; Code: + +(require 'ert) +(require 'cl-lib) +(require 'latex) + +(defmacro latex-modify-test--with-temp-buffer (contents &rest body) + "Create a temporary LaTeX buffer with CONTENTS and execute BODY. +This macro is used to set up a test environment for `LaTeX-modify-math'." + (declare (indent 1) (debug t)) + `(with-temp-buffer + (LaTeX-mode) + (insert ,contents) + (goto-char (point-min)) + (cl-letf (((symbol-function 'preview-clearout-at-point) #'ignore)) + ,@body))) + +(ert-deftest LaTeX-modify-math-inline-bracket-period () + "Convert \\=3D\\[...\\=3D\\] to $..$ and keep trailing period." + (latex-modify-test--with-temp-buffer + "We have\n\\[ a+b =3D c. \\]" + (search-forward "b") + (LaTeX-make-inline) + (should (equal (buffer-string) "We have $a+b =3D c$.")))) + +(ert-deftest LaTeX-modify-math-inline-double-dollar () + "Convert $$..$$ to $..$." + (latex-modify-test--with-temp-buffer + "$$x!$$" + (search-forward "x") + (LaTeX-make-inline) + (should (equal (buffer-string) "$x$!")))) + +(ert-deftest LaTeX-modify-math-inline-electric-math () + "Respect `TeX-electric-math'." + (let ((TeX-electric-math '("\\(" . "\\)"))) + (latex-modify-test--with-temp-buffer + "\\[ x \\]" + (search-forward "x") + (LaTeX-make-inline) + (should (equal (buffer-string) "\\(x\\)"))))) + +(ert-deftest LaTeX-modify-math-inline-equation-env () + "Convert equation environment, drop \\label, keep comma." + (latex-modify-test--with-temp-buffer + "Hi.\n\nWe have\n\\begin{equation}\n\\label{l}x+y,\n\\end{equation}\= n" + (search-forward "x") + (let ((TeX-electric-math '("\\(" . "\\)"))) + (LaTeX-make-inline) + (should (equal (buffer-string) "Hi.\n\nWe have \\(x+y\\),\n"))))) + +(ert-deftest LaTeX-modify-math-inline-noop () + "Call inside inline math leaves buffer unchanged." + (latex-modify-test--with-temp-buffer + "Already $z$ inline." + (search-forward "z") + (LaTeX-make-inline) + (should (equal (buffer-string) "Already $z$ inline.")))) + +(ert-deftest LaTeX-modify-math-inline-paren-to-dollar () + "Convert \\(...\\) to $...$." + (latex-modify-test--with-temp-buffer + "Text \\(a + b\\) more text." + (search-forward "a") + (let ((TeX-electric-math nil)) + (LaTeX-make-inline) + (should (equal (buffer-string) "Text $a + b$ more text."))))) + +(ert-deftest LaTeX-modify-math-inline-multiline-equation () + "Convert multiline equation environment to inline, removing labels." + (latex-modify-test--with-temp-buffer + "Before\n\\begin{equation}\n x + y =3D z\n \\label{eq:test}\n\\end= {equation}\nAfter" + (search-forward "x") + (LaTeX-make-inline) + (should (equal (buffer-string) "Before $x + y =3D z$ After")))) + +(ert-deftest LaTeX-modify-math-inline-punctuation-semicolon () + "Move semicolon outside inline math." + (latex-modify-test--with-temp-buffer + "\\[ x + y; \\]" + (search-forward "x") + (LaTeX-make-inline) + (should (equal (buffer-string) "$x + y$;")))) + +(ert-deftest LaTeX-modify-math-inline-multiple-punctuation () + "Handle multiple punctuation marks." + (latex-modify-test--with-temp-buffer + "\\[ result?! \\]" + (search-forward "result") + (LaTeX-make-inline) + (should (equal (buffer-string) "$result$?!")))) + +(ert-deftest LaTeX-modify-math-inline-whitespace-preservation () + "Preserve surrounding whitespace appropriately." + (latex-modify-test--with-temp-buffer + "Text \\[ a + b \\] more." + (search-forward "a") + (LaTeX-make-inline) + (should (equal (buffer-string) "Text $a + b$ more.")))) + +(ert-deftest LaTeX-modify-math-inline-empty-lines () + "Remove empty lines from display math when converting." + (latex-modify-test--with-temp-buffer + "\\[\n\n x =3D y \n\n\\]" + (search-forward "x") + (LaTeX-make-inline) + (should (equal (buffer-string) "$x =3D y$")))) + +(ert-deftest LaTeX-modify-math-dollar-to-bracket () + "Convert $...$ to \\=3D\\[...\\=3D\\]." + (latex-modify-test--with-temp-buffer + "Text $x + y$ more." + (search-forward "+") + (LaTeX-modify-math "\\[") + (should (equal (buffer-string) "Text\n\\[\n x + y\n\\]\nmore.")))) + +(ert-deftest LaTeX-modify-math-paren-to-double-dollar () + "Convert \\(...\\) to $$...$$." + (latex-modify-test--with-temp-buffer + "Text \\(a =3D b\\) end." + (search-forward "a") + (LaTeX-modify-math "$$") + (should (equal (buffer-string) "Text\n$$\na =3D b\n$$\nend.")))) + +(ert-deftest LaTeX-modify-math-bracket-to-equation () + "Convert \\=3D\\[...\\=3D\\] to equation environment." + (latex-modify-test--with-temp-buffer + "\\[ f(x) =3D x^2 \\]" + (search-forward "f") + (LaTeX-modify-math "equation") + (should (equal (buffer-string) "\\begin{equation}\n f(x) =3D x^2\n\\e= nd{equation}")))) + +(ert-deftest LaTeX-modify-math-point-inline-to-display-after-content () + "Point after inline content preserved after display conversion." + (latex-modify-test--with-temp-buffer + "A $x+y$ B" + (search-forward "y") + (LaTeX-modify-math "\\[") + (should (looking-back "y" (1- (point)))) + (should (looking-at "\n[[:space:]]*\\\\\\]")))) + +(ert-deftest LaTeX-modify-math-point-inline-to-display-before-content () + "Point before inline content preserved after display conversion." + (latex-modify-test--with-temp-buffer + "A $x+y$ B" + (search-forward "$") + (LaTeX-modify-math "\\[") + (looking-at "x") + (should (looking-at "x")))) + +(ert-deftest LaTeX-modify-math-point-display-to-inline-after-content () + "Point after display content preserved after inline conversion." + (latex-modify-test--with-temp-buffer + "\\[\n x + y\n\\]" + (goto-char (point-min)) + (re-search-forward "y") + (LaTeX-make-inline) + (should (looking-back "y" (1- (point)))) + (should (looking-at "\\$")))) + +(ert-deftest LaTeX-modify-math-point-display-to-inline-before-content () + "Point before display content preserved after inline conversion." + (latex-modify-test--with-temp-buffer + "\\[\n x + y\n\\]" + (goto-char (point-min)) + (re-search-forward "x") + (forward-char -1) + (LaTeX-make-inline) + (should (looking-at "x")))) + +(ert-deftest LaTeX-modify-math-point-multiline-roundtrip () + "Point before/after content preserved for round-trip conversion." + (latex-modify-test--with-temp-buffer + "foo $x+y$ bar" + (search-forward "y") + (backward-char) + (LaTeX-modify-math "\\[") + (should (looking-at "y")) + (LaTeX-make-inline) + (should (looking-at "y")))) + +;;; latex-modify-math-test.el ends here --=20 2.39.3 (Apple Git-145) --=-=-=-- From unknown Sat Jun 14 19:44:59 2025 X-Loop: help-debbugs@gnu.org Subject: bug#78586: TeX-make-inline Resent-From: Ikumi Keita Original-Sender: "Debbugs-submit" Resent-CC: bug-auctex@gnu.org Resent-Date: Mon, 09 Jun 2025 18:24:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 78586 X-GNU-PR-Package: auctex X-GNU-PR-Keywords: To: "Paul D. Nelson" Cc: arash@gnu.org, 78586@debbugs.gnu.org Received: via spool by 78586-submit@debbugs.gnu.org id=B78586.17494934215718 (code B ref 78586); Mon, 09 Jun 2025 18:24:02 +0000 Received: (at 78586) by debbugs.gnu.org; 9 Jun 2025 18:23:41 +0000 Received: from localhost ([127.0.0.1]:57203 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1uOh9o-0001U8-KW for submit@debbugs.gnu.org; Mon, 09 Jun 2025 14:23:41 -0400 Received: from smtp1a.inetd.co.jp ([210.129.88.11]:49350) by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.84_2) (envelope-from ) id 1uOh9l-0001TV-CF for 78586@debbugs.gnu.org; Mon, 09 Jun 2025 14:23:38 -0400 Received: from localhost (42-144-37-89.rev.home.ne.jp [42.144.37.89]) by smtp1a.inetd.co.jp (Postfix) with ESMTPSA id 170625C; Tue, 10 Jun 2025 03:23:34 +0900 (JST) From: Ikumi Keita In-reply-to: References: Comments: In-reply-to "Paul D. Nelson" message dated "Sun, 08 Jun 2025 16:05:19 +0200." X-Mailer: MH-E 8.6+git; nmh 1.8; Emacs 30.1 MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-ID: <16978.1749493414.1@localhost> Date: Tue, 10 Jun 2025 03:23:34 +0900 Message-ID: <16979.1749493414@localhost> X-Spam-Score: 0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Hi Paul, >>>>> "Paul D. Nelson" writes: > I've updated the attached patch with docs (so I think it's now in good > shape, but I always welcome feedback on my texinfo). Thank you. Now I agree with your perspective. Please commit it into the git repo and close the bug. Regards, Ikumi Keita #StandWithUkraine #StopWarInUkraine #Gaza #StopMassiveKilling #CeasefireNOW From unknown Sat Jun 14 19:44:59 2025 MIME-Version: 1.0 X-Mailer: MIME-tools 5.505 (Entity 5.505) X-Loop: help-debbugs@gnu.org From: help-debbugs@gnu.org (GNU bug Tracking System) To: "Paul D. Nelson" Subject: bug#78586: closed (Re: bug#78586: TeX-make-inline) Message-ID: References: X-Gnu-PR-Message: they-closed 78586 X-Gnu-PR-Package: auctex Reply-To: 78586@debbugs.gnu.org Date: Mon, 09 Jun 2025 19:03:02 +0000 Content-Type: multipart/mixed; boundary="----------=_1749495782-23673-1" This is a multi-part message in MIME format... ------------=_1749495782-23673-1 Content-Disposition: inline Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Your bug report #78586: TeX-make-inline which was filed against the auctex package, has been closed. The explanation is attached below, along with your original report. If you require more details, please reply to 78586@debbugs.gnu.org. --=20 78586: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=3D78586 GNU Bug Tracking System Contact help-debbugs@gnu.org with problems ------------=_1749495782-23673-1 Content-Type: message/rfc822 Content-Disposition: inline Content-Transfer-Encoding: 7bit Received: (at 78586-done) by debbugs.gnu.org; 9 Jun 2025 19:02:10 +0000 Received: from localhost ([127.0.0.1]:57501 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1uOhl4-00064Y-CH for submit@debbugs.gnu.org; Mon, 09 Jun 2025 15:02:10 -0400 Received: from mail-lf1-x12a.google.com ([2a00:1450:4864:20::12a]:55701) by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.84_2) (envelope-from ) id 1uOhl1-00063T-Kg for 78586-done@debbugs.gnu.org; Mon, 09 Jun 2025 15:02:08 -0400 Received: by mail-lf1-x12a.google.com with SMTP id 2adb3069b0e04-5533a86a134so4438111e87.3 for <78586-done@debbugs.gnu.org>; Mon, 09 Jun 2025 12:02:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1749495721; x=1750100521; darn=debbugs.gnu.org; h=mime-version:message-id:date:in-reply-to:subject:cc:to:from:from:to :cc:subject:date:message-id:reply-to; bh=YO7fcmC92gBM/mbMBIqmPjBDcN+6Rkmzz2trmHL6CuU=; b=OD0YnHF4r6SVCBJoOZnv0bu3uWLaQlGvm0PB//UuLGfnbBOAJ481r5Y3y5N3qEh1UE +/hgYzHC38LbTCMaiWfosedfK97MFZaJ10s6WD7Zb4M4xzyDKe9efXJ44X2zJGvITzry ttx40JKK9CDnoi2JzgCXxkaLShq9phaxoYztxqvplXjeC5W9mQ4ZXsk6C8u8b306mpxR SbIsFXVgfaLgrN0wkuzjvolVNJECM3zSFzhU8ghF1H9J3l+VCAdT/kTi99PLYbmGh/2w pe/OVmPXhGjYcGNBF1mddJnVp1tZgfOOTx5RXW6QvRG5lRqkNEQOI1ONVGhYt5/KRTY+ 7jAQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1749495721; x=1750100521; h=mime-version:message-id:date:in-reply-to:subject:cc:to:from :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=YO7fcmC92gBM/mbMBIqmPjBDcN+6Rkmzz2trmHL6CuU=; b=fWwe0jQl24wQ491KQksbKWaej3tlGJfw+YRF7WqY01rP1oDBmFdZACZTefAW17ktU5 826TpwRlFRzwnEvGTkMMvTHeciE2y1XwSah3rWlERAWrKngMFcf+MxVxTBwhXAfyKCFX N6tv0W1cUJNK5h9k+Ek9wNuC3VoPtDMd20j/loTX7IIjXgLeu4qBFuGKAdTwiUht+5c2 c3lwgPY1BRzgZ3yazA5DLHsZ/4rmjNaQEODaU9DYwZBO5KcVl1Ddf/fMu+EF3lLl4wBr FE/SqR9g0e68dvH+vHPpVRKv/qFh3Qn0VVkPXo3VlrbNg7DZKuihAc7fsGdF1I9Y8lPs p6/g== X-Forwarded-Encrypted: i=1; AJvYcCUcKlbgcTGK8Hg6e+PFOlIxJDR0/6Oqz5iTmX57v4zBEwpMcJFrYu30LN4m9Q/8kaxQUTngfg0YqSSU@debbugs.gnu.org X-Gm-Message-State: AOJu0YxdIwCjGNU+bbrfuq+ixSrdDUKkwNEF4ZWsP60PTmk11Us72215 N4qzot5SDLmkmctFR8Uwfp2BeZ+vtX+ioYHH6dyE9DL30cR1/oAEwRwv X-Gm-Gg: ASbGnctP7E0k+D0hJEkud9Maa0iyyhoiHw4XxZnXats/m5E6Qynr2qSVoky8AQVTg02 e+vuHrklHlv+yNwM0oKFwaoMeFPH3/yxhNrG4ZDRlxWobq9iNeG9JImcmCA3qPAYRy8HFWchs0y 6dbjAcrk8wWu/kCqAl1IE8pBQ7Q9ODZaC7UGVPFDi3YneLz7EPrWB0uO7M/mw5Lxs2k2vBWVfI1 BdznOHd4iFL5jeCgVWMVsvS7c6+1wHWMF8lolbDBJbQLJvL1FxzHM47NPQw8+/QK8M+fvH/v+0+ kp6WzkLkMUceIq0cFAXa2jqBNzqXmnBvFJe0cqyDmjXeZ5n9NuIzSwcp X-Google-Smtp-Source: AGHT+IHNIKN9fG7y36H0u+y634sHnVKqEXRTPIAUwxXL+9XThGOs5qTFo1gqo4vWmjFkKoq3vbx1nQ== X-Received: by 2002:a05:6512:4002:b0:553:2bf7:77be with SMTP id 2adb3069b0e04-55366be2d0fmr3241636e87.22.1749495720824; Mon, 09 Jun 2025 12:02:00 -0700 (PDT) Received: from localhost ([185.229.155.48]) by smtp.gmail.com with UTF8SMTPSA id 2adb3069b0e04-5536772a4ebsm1265183e87.153.2025.06.09.12.01.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 09 Jun 2025 12:02:00 -0700 (PDT) From: "Paul D. Nelson" To: Ikumi Keita Subject: Re: bug#78586: TeX-make-inline In-Reply-To: <16979.1749493414@localhost> (message from Ikumi Keita on Tue, 10 Jun 2025 03:23:34 +0900) Date: Mon, 09 Jun 2025 21:01:59 +0200 Message-ID: MIME-Version: 1.0 Content-Type: text/plain X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 78586-done Cc: arash@gnu.org, 78586-done@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Thanks Ikumi, I pushed the change and hope this message closes it! Paul ------------=_1749495782-23673-1 Content-Type: message/rfc822 Content-Disposition: inline Content-Transfer-Encoding: 7bit Received: (at submit) by debbugs.gnu.org; 25 May 2025 14:02:17 +0000 Received: from localhost ([127.0.0.1]:46132 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1uJBvc-0006nH-Nq for submit@debbugs.gnu.org; Sun, 25 May 2025 10:02:17 -0400 Received: from lists.gnu.org ([2001:470:142::17]:59304) by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.84_2) (envelope-from ) id 1uJBvY-0006lu-6i for submit@debbugs.gnu.org; Sun, 25 May 2025 10:02:13 -0400 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 1uJBvH-0002Yl-Ls for bug-auctex@gnu.org; Sun, 25 May 2025 10:01:56 -0400 Received: from mail-ej1-x636.google.com ([2a00:1450:4864:20::636]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1uJBvG-000793-0D for bug-auctex@gnu.org; Sun, 25 May 2025 10:01:55 -0400 Received: by mail-ej1-x636.google.com with SMTP id a640c23a62f3a-ad574992fcaso261026466b.1 for ; Sun, 25 May 2025 07:01:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1748181712; x=1748786512; darn=gnu.org; h=mime-version:message-id:date:subject:to:from:from:to:cc:subject :date:message-id:reply-to; bh=kAQk0CAA/VgcEl1FrkJxKqKbFlbFgCr6hr4TtQznZcA=; b=SBaCgrtmLxbCEKNpI9iNRdzeilh7jRE5bjRmsHjsSH+i+OcrsOXxE/nW8LTDkzZIWL A5CitRvBIsm7e6IBIdFMnFSCb0OIQUpPeq0/ZE3h8whaamqrBSUELC7+X/7P1zbpOeVs Ikb2RBwVF6wegP68kjky6KK65YiFsAdAMsO94ge4iAfowXq/laCpQkcaTpEIOvZjZAws Yf6WjkVME7ag+2V7k7uqYyfWaP5WjvwXdkvy0Pknlxl+RQ7T+vG1brNE99NFhchEFuTv NRbuhPK+yVtQlYtwjbrnjj4Ll9/W4UKM+cf5ilARGt1sr6IsfRsoU2odXjNqb814SUCZ TrhA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1748181712; x=1748786512; h=mime-version:message-id:date:subject:to:from:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=kAQk0CAA/VgcEl1FrkJxKqKbFlbFgCr6hr4TtQznZcA=; b=tUy3GB7YrVOPlFR4AAVRtaKJnLoCVFLrbhDkxmcthoyzQk44K760uB0mAQtLIPeks+ HGmJXf0m0kR1kqUPcUj2vXBLgjQxj3eaV3SDo8qdoiubrMGJeGOzMKLEXw0zl8QcJyXw +jobLkOx1pNy9Ty4MKVcPSfTYDKFxuFRmSqZDV7PyxYGQmOxXtZMprVP2LDcLh7FXJrM 9BbcHzzvoy1u4ldxEoY+hRu5G4Gqvo2lHiZSkVMvI8+C7kgNuZa9RLp30AXXlx9Zkgk4 XldtEVWckr1FCtUIaDLhgJJAjfpdsDgJj9uo6yxg7hEV42SNnHmQw71nfFs0QViHYsWr 3XXQ== X-Gm-Message-State: AOJu0Yygn0p9t8c8VKYVdDyK8Xsq6diQmJ2XDUP2nqrovLK8TrR6RBUg Xk9PViBfKjADkBmXiVrjRZZiwVWEFPLvpYXYIMOCOM4Nr2cpFXwZNRqmYONSKQMm X-Gm-Gg: ASbGncsB9jFNzFoQEEgtEf4yf8RCaUBeY8Z1ytN3fLQoQFjnrZ/1CyjIY4B1j01nLmt 3xBAk8JwfPhS4XZ9MyQzDhlXE0xwc4F8ri6w2mPOgiEKmwk7uIJJ43aSyTgw2U3J+BoznBHM29v GxFXnrQNte9bTCeClJ2wF5OmGsBQBujC3lBbSIe0t2+Kq73U2aQIJ4lJLIuAqWl7lAm3NuBbvSd 6nOw6VUbT0uZfqWJfLp57yqpftMVKxGgxYMTtgndJyqvjiqCEQMbyr88JvD2127Fu3nU9VkJe/q Pui8f/YmufKWarjXO2WB6etgbMtznkhCCunklHqWMroZst+lk/Bi6cR6MmaaQMW2T+jOhcir+9M vlZU= X-Google-Smtp-Source: AGHT+IGSlTw6ILExPqOX9+Es9+jXiMTc3Lj0Xs7L+HFxt63T7BUCpwjF4hsdyBgV9PMdS5RW3NmBzA== X-Received: by 2002:a17:906:338d:b0:ad5:6422:4ef4 with SMTP id a640c23a62f3a-ad85b2a49b5mr365846666b.55.1748181711712; Sun, 25 May 2025 07:01:51 -0700 (PDT) Received: from localhost ([185.229.154.237]) by smtp.gmail.com with UTF8SMTPSA id a640c23a62f3a-ad52d4cbe90sm1522729966b.165.2025.05.25.07.01.51 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 25 May 2025 07:01:51 -0700 (PDT) From: "Paul D. Nelson" To: bug-auctex@gnu.org Subject: TeX-make-inline Date: Sun, 25 May 2025 16:01:50 +0200 Message-ID: MIME-Version: 1.0 Content-Type: text/plain Received-SPF: pass client-ip=2a00:1450:4864:20::636; envelope-from=ultrono@gmail.com; helo=mail-ej1-x636.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Spam-Score: 1.0 (+) X-Debbugs-Envelope-To: submit X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -0.0 (/) Hi Arash and all, We had discussed in an earlier thread (bug#78006) the possibility of adding some of my editing commands to AUCTeX (as standalone commands, without default binds). We could start with this one, discussed a bit in that thread: --8<---------------cut here---------------start------------->8--- (defcustom TeX-make-inline-delims '("$" . "$") "Delimiters for `TeX-make-inline' to surround inline LaTeX math." :type '(radio (const :tag "Dollar ($...$)" ("$" . "$")) (const :tag "Paren (\\(...\\))" ("\\(" . "\\)")) (cons :tag "Custom delimiters" (string :tag "Left") (string :tag "Right")))) (defun TeX-make-inline () "Convert LaTeX display math environment at point to inline math. Removes the enclosing math environment (such as \\[...\\] or \\begin{equation}...\\end{equation}). Replaces it with inline math surrounded by `TeX-make-inline-delims', fitting the result onto one line. Leaves any trailing punctuation outside the math delimiters." (interactive) (when (texmathp) (when (fboundp 'preview-clearout-at-point) (preview-clearout-at-point)) (save-excursion (let* ((env (car texmathp-why)) (pos (cdr texmathp-why)) (delims TeX-make-inline-delims)) (cond ((member env '("\\(" "$"))) ((member env '("\\[" "$$")) (goto-char pos) (delete-char 2) (let ((start (point)) (end-delim (if (equal env "\\[") "\\]" "$$"))) (search-forward end-delim) (delete-char -2) (TeX-make-inline--finalize-region start (point) delims))) (t (goto-char pos) (kill-line) (let ((start (point))) (search-forward (concat "\\end{" env "}")) (beginning-of-line) (kill-line) (TeX-make-inline--finalize-region start (point) delims)))))))) (defun TeX-make-inline--finalize-region (start end delims) "Finalize the inline conversion from START to END using DELIMS." (save-restriction (narrow-to-region start end) (whitespace-cleanup) (goto-char (point-min)) (let ((re (concat "\\(?:" (mapconcat #'identity (if (boundp 'reftex-label-regexps) reftex-label-regexps '("\\\\label{[^}]*")) "\\|") "\\)"))) (while (re-search-forward re nil t) (replace-match ""))) (goto-char (point-min)) (while (looking-at "\\s-*$") (delete-line)) (beginning-of-line-text) (delete-region (point-min) (point)) (goto-char (point-max)) (while (and (> (point) (point-min)) (progn (forward-line -1) (looking-at "\\s-*$"))) (delete-line)) (end-of-line) (skip-chars-backward " \t") (delete-region (point) (point-max)) (goto-char (point-min)) (insert (car delims)) (goto-char (point-max)) (insert "\n") (backward-char) (while (looking-back "[.,;:!?]" 5) (backward-char)) (insert (cdr delims)) (while (> (count-lines (point-min) (point-max)) 1) (join-line)))) --8<---------------cut here---------------end--------------->8--- I haven't prepared this as a patch because I'm not sure where to put it or where to document it. I looked around, and couldn't find a natural place. If no better idea comes to mind, then perhaps some new "miscellaneous commands" section of latex.el, with a corresponding section in the manual? For what it's worth, there are a couple of other editing-related commands I'd be inclined to propose. Any feedback welcome. Thanks, best, Paul ------------=_1749495782-23673-1-- From unknown Sat Jun 14 19:44:59 2025 X-Loop: help-debbugs@gnu.org Subject: bug#78586: TeX-make-inline Resent-From: Arash Esbati Original-Sender: "Debbugs-submit" Resent-CC: bug-auctex@gnu.org Resent-Date: Wed, 11 Jun 2025 06:49:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 78586 X-GNU-PR-Package: auctex X-GNU-PR-Keywords: To: 78586@debbugs.gnu.org Cc: ultrono@gmail.com Received: via spool by 78586-submit@debbugs.gnu.org id=B78586.174962452230699 (code B ref 78586); Wed, 11 Jun 2025 06:49:02 +0000 Received: (at 78586) by debbugs.gnu.org; 11 Jun 2025 06:48:42 +0000 Received: from localhost ([127.0.0.1]:45772 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1uPFGL-0007z5-VY for submit@debbugs.gnu.org; Wed, 11 Jun 2025 02:48:42 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:47398) by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.84_2) (envelope-from ) id 1uPFGJ-0007yM-Qp for 78586@debbugs.gnu.org; Wed, 11 Jun 2025 02:48:40 -0400 Received: from fencepost.gnu.org ([2001:470:142:3::e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uPFGC-0003Re-6C; Wed, 11 Jun 2025 02:48:33 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org; s=fencepost-gnu-org; h=MIME-Version:Date:References:In-Reply-To:Subject:To: From; bh=4FvTnDOn+Y4w9Gf30RpzWjbk8Dl7mCYWmXIISLoFoc4=; b=VnGrcFQepq6wUKE7Ci64 TQRHJV0WHskYnQJ77wdHjFr4rV475uIj79wqc2eMpkGLyn1e91AvvZA+E0frrXtat0sDMVgHBEohv PYR7kuJOtkAWWP5eDxop0by9TojLCGfo1QXrRrOFKzz/lk+/dRfMdMN0eUM3XfZyws8gGrxlX10e7 T/jhlmEVJ6BXGUhGm/XQNond/EioYBz8PQGJVj0UXpfqYUUi52v2s4Ktyy+DX13NfeFu1LUVGxw8s MelEb2HwOKvtW/T5o4jj2zuhh8a0nsbO3UXaZtDlcOZEdB+XF+LRT0nLIklI0NwaGN1NwrjDtRgo3 yIMx0HDzlLEIuw==; From: Arash Esbati In-Reply-To: References: Date: Wed, 11 Jun 2025 08:48:27 +0200 Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: text/plain X-Spam-Score: -2.3 (--) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) "Paul D. Nelson" writes: > Thanks Ikumi, I pushed the change and hope this message closes it! Thanks Paul. I also added an entry about the new commands to NEWS.org. Best, Arash