From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Tassilo Horn Newsgroups: gmane.emacs.bugs Subject: bug#19267: 25.0.50; Enhance cycle-spacing with a state where only whitespace after point is deleted Date: Fri, 13 May 2022 23:11:26 +0200 Message-ID: <87tu9tds7o.fsf@gnu.org> References: <87o801z125.fsf@gnus.org> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="31578"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: mu4e 1.7.20; emacs 29.0.50 Cc: Robert Pluim , 19267@debbugs.gnu.org To: Lars Ingebrigtsen Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Fri May 13 23:44:17 2022 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1npd54-0007t7-Po for geb-bug-gnu-emacs@m.gmane-mx.org; Fri, 13 May 2022 23:44:15 +0200 Original-Received: from localhost ([::1]:36948 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1npd53-0002oC-FF for geb-bug-gnu-emacs@m.gmane-mx.org; Fri, 13 May 2022 17:44:13 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:40964) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1npd4t-0002mZ-5B for bug-gnu-emacs@gnu.org; Fri, 13 May 2022 17:44:03 -0400 Original-Received: from debbugs.gnu.org ([209.51.188.43]:51320) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1npd4s-00058S-Dd for bug-gnu-emacs@gnu.org; Fri, 13 May 2022 17:44:02 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1npd4s-0004oT-C6 for bug-gnu-emacs@gnu.org; Fri, 13 May 2022 17:44:02 -0400 X-Loop: help-debbugs@gnu.org Resent-From: Tassilo Horn Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Fri, 13 May 2022 21:44:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 19267 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: moreinfo Original-Received: via spool by 19267-submit@debbugs.gnu.org id=B19267.165247819818401 (code B ref 19267); Fri, 13 May 2022 21:44:02 +0000 Original-Received: (at 19267) by debbugs.gnu.org; 13 May 2022 21:43:18 +0000 Original-Received: from localhost ([127.0.0.1]:45211 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1npd49-0004mi-Ve for submit@debbugs.gnu.org; Fri, 13 May 2022 17:43:18 -0400 Original-Received: from eggs.gnu.org ([209.51.188.92]:47470) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1npd48-0004mT-Cu for 19267@debbugs.gnu.org; Fri, 13 May 2022 17:43:17 -0400 Original-Received: from fencepost.gnu.org ([2001:470:142:3::e]:43944) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1npd42-00051L-W3; Fri, 13 May 2022 17:43:11 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org; s=fencepost-gnu-org; h=MIME-Version:In-reply-to:Date:Subject:To:From: References; bh=HCi4YxjufQcSvI1qYzYInMhVWEFjstUfzGHZTq/BJu0=; b=AoKl8AY4JTxB1F 7QjCNWGS4wHtxEASRzb8wlIsWybtBpIF9uoBk7NsES9XElct5pyh9Cg4FRsJpKw/lLgwZHLfZuBNu +lE8htsKyS3xxI7D1vTdIVoduIYMNvJSdlHtOsnNw15fY7YWP7UsMyAen9y+z/PWHw/dJxjTxHAEK VJmiCfoM+79QZE+FG5pNMRiZpZM5g5CDw7+7yVLtLRJSejZA6+bexJQLDKI2EQJ7PthWfNuzrwu1o lcZU9euRZS6zfLkM2V0lHNdG112p7Vx07YJoPMbV0clMrG20ApKvYUHgpwhPnCxazOgHXyapDkAHQ JVG050AWz54q/482ampg==; Original-Received: from auth1-smtp.messagingengine.com ([66.111.4.227]:38375) by fencepost.gnu.org with esmtpsa (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1npd42-0004RP-P9; Fri, 13 May 2022 17:43:10 -0400 Original-Received: from compute5.internal (compute5.nyi.internal [10.202.2.45]) by mailauth.nyi.internal (Postfix) with ESMTP id 58E1827C0054; Fri, 13 May 2022 17:43:10 -0400 (EDT) Original-Received: from mailfrontend1 ([10.202.2.162]) by compute5.internal (MEProxy); Fri, 13 May 2022 17:43:10 -0400 X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvfedrhedtucetufdoteggodetrfdotffvucfrrh hofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgenuceurghi lhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmnecujfgurh epfhgfhffvvefuffgjkfggtgesmhdtreertdertdenucfhrhhomhepvfgrshhsihhlohcu jfhorhhnuceothhsughhsehgnhhurdhorhhgqeenucggtffrrghtthgvrhhnpeeihfetff eiledufeffffekveegffehgefhieettdejgefgveeiueduveehffffteenucevlhhushht vghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpehthhhorhhnodhmvghsmh htphgruhhthhhpvghrshhonhgrlhhithihqdekieejfeekjeekgedqieefhedvleekqdht shguhheppehgnhhurdhorhhgsehfrghsthhmrghilhdrfhhm X-ME-Proxy: Original-Received: by mail.messagingengine.com (Postfix) with ESMTPA; Fri, 13 May 2022 17:43:09 -0400 (EDT) In-reply-to: <87o801z125.fsf@gnus.org> X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: "bug-gnu-emacs" Xref: news.gmane.io gmane.emacs.bugs:232198 Archived-At: --=-=-= Content-Type: text/plain Lars Ingebrigtsen writes: >> I'll make it so that the prefix arg is passed on in the cycle so M-- >> M-SPC M-SPC will delete all space including newline before point. >> IMO, that's better than a separate action. > > I want a separate action, because the current `M-- M-SPC' action is > basically the only one I use, and I want to be able to just type > `M-SPC' to get it. Would it be ok for you to define it in your init file? I've documented the positive arg = tabs/spaces, negative arg = tabs/spaces/newlines as a general contract of all predefined actions (see new patch below) and your favorite action would immediately violate it... >>> delete-space-before/after could also care about the numerical >>> prefix? >> >> Yes, in the sense that negative means "including newlines". > > I meant in the same way just-one-space does. I.e., leave 4 space after > point if given a 4 prefix, etc. No, at least not yet. But if they did, you would need to always give an explicit prefix arg when you really want to delete all spaces before/after point because the default value of a numerical prefix arg is 1. Bye, Tassilo --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-Improve-cycle-spacing.patch >From 1550ec47094667158292122bc7bb0114d0c48cbd Mon Sep 17 00:00:00 2001 From: Tassilo Horn Date: Thu, 12 May 2022 23:24:47 +0200 Subject: [PATCH] Improve cycle-spacing --- doc/emacs/killing.texi | 25 +++-- etc/NEWS | 5 + lisp/bindings.el | 2 +- lisp/simple.el | 230 +++++++++++++++++++++++++++++------------ 4 files changed, 184 insertions(+), 78 deletions(-) diff --git a/doc/emacs/killing.texi b/doc/emacs/killing.texi index 2fd2d21dd3..30025134eb 100644 --- a/doc/emacs/killing.texi +++ b/doc/emacs/killing.texi @@ -111,24 +111,27 @@ Deletion @kindex M-\ @findex delete-horizontal-space -@kindex M-SPC -@findex just-one-space -@findex cycle-spacing - The other delete commands are those that delete only whitespace +The other delete commands are those that delete only whitespace characters: spaces, tabs and newlines. @kbd{M-\} (@code{delete-horizontal-space}) deletes all the spaces and tab characters before and after point. With a prefix argument, this only -deletes spaces and tab characters before point. @kbd{M-@key{SPC}} -(@code{just-one-space}) does likewise but leaves a single space before +deletes spaces and tab characters before point. + +@findex just-one-space +@code{just-one-space} does likewise but leaves a single space before point, regardless of the number of spaces that existed previously (even if there were none before). With a numeric argument @var{n}, it leaves @var{n} spaces before point if @var{n} is positive; if @var{n} is negative, it deletes newlines in addition to spaces and tabs, -leaving @minus{}@var{n} spaces before point. The command @code{cycle-spacing} -acts like a more flexible version of @code{just-one-space}. It -does different things if you call it repeatedly in succession. -The first call acts like @code{just-one-space}, the next removes -all whitespace, and a third call restores the original whitespace. +leaving @minus{}@var{n} spaces before point. + +@kindex M-SPC +@findex cycle-spacing +@vindex cycle-spacing-actions +The command @code{cycle-spacing} (@kbd{M-@key{SPC}}) acts like a more +flexible version of @code{just-one-space}. It performs different +space cleanup actions if you call it repeatedly in succession as +defined by @code{cycle-spacing-actions}. @kbd{C-x C-o} (@code{delete-blank-lines}) deletes all blank lines after the current line. If the current line is blank, it deletes all diff --git a/etc/NEWS b/etc/NEWS index d93a79ed36..2e7c408607 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -672,6 +672,11 @@ recreate it anew next time 'imenu' is invoked. * Editing Changes in Emacs 29.1 ++++ +** M-SPC is now bound to 'cycle-spacing' (formerly it was 'just-one-space'). +The actions performed by 'cycle-spacing' and their order can now be +customized via 'cycle-spacing-actions'. + --- ** 'scroll-other-window' and 'scroll-other-window-down' now respects remapping. These commands (bound to 'C-M-v' and 'C-M-V') used to scroll the other diff --git a/lisp/bindings.el b/lisp/bindings.el index bfe5ba8623..ed1325e326 100644 --- a/lisp/bindings.el +++ b/lisp/bindings.el @@ -990,7 +990,7 @@ esc-map (define-key esc-map "\\" 'delete-horizontal-space) (define-key esc-map "m" 'back-to-indentation) (define-key ctl-x-map "\C-o" 'delete-blank-lines) -(define-key esc-map " " 'just-one-space) +(define-key esc-map " " 'cycle-spacing) (define-key esc-map "z" 'zap-to-char) (define-key esc-map "=" 'count-words-region) (define-key ctl-x-map "=" 'what-cursor-position) diff --git a/lisp/simple.el b/lisp/simple.el index 3812f6d8c6..325b1bb506 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -1072,15 +1072,24 @@ delete-horizontal-space "Delete all spaces and tabs around point. If BACKWARD-ONLY is non-nil, delete them only before point." (interactive "*P") + (delete-space--internal " \t" backward-only)) + +(defun delete-all-space (&optional backward-only) + "Delete all spaces, tabs, and newlines around point. +If BACKWARD-ONLY is non-nil, delete them only before point." + (interactive "*P") + (delete-space--internal " \t\r\n" backward-only)) + +(defun delete-space--internal (chars backward-only) (let ((orig-pos (point))) (delete-region (if backward-only - orig-pos + orig-pos (progn - (skip-chars-forward " \t") - (constrain-to-field nil orig-pos t))) + (skip-chars-forward chars) + (constrain-to-field nil orig-pos t))) (progn - (skip-chars-backward " \t") + (skip-chars-backward chars) (constrain-to-field nil orig-pos))))) (defun just-one-space (&optional n) @@ -1088,73 +1097,162 @@ just-one-space If N is negative, delete newlines as well, leaving -N spaces. See also `cycle-spacing'." (interactive "*p") - (cycle-spacing n nil 'single-shot)) + (let ((orig-pos (point)) + (skip-characters (if (and n (< n 0)) " \t\n\r" " \t")) + (num (abs (or n 1)))) + (skip-chars-backward skip-characters) + (constrain-to-field nil orig-pos) + (let* ((num (- num (skip-chars-forward " " (+ num (point))))) + (mid (point)) + (end (progn + (skip-chars-forward skip-characters) + (constrain-to-field nil orig-pos t)))) + (delete-region mid end) + (insert (make-string num ?\s))))) (defvar cycle-spacing--context nil - "Store context used in consecutive calls to `cycle-spacing' command. -The first time `cycle-spacing' runs, it saves in this variable: -its N argument, the original point position, and the original spacing -around point.") + "Stored context used in consecutive calls to `cycle-spacing' command. +The value is a property list with the following elements: +- `:orig-pos' The original position of point when starting the + sequence. +- `:whitespace-string' All whitespace characters around point + including newlines. +- `:n' The prefix arg given to the initial invocation + which is reused for all actions in this cycle. +- `:last-action' The last action performed in the cycle.") + +(defcustom cycle-spacing-actions + '( just-one-space + delete-space-after + delete-space-before + delete-all-space + restore) + "List of actions cycled through by `cycle-spacing'. +Supported values are: +- `just-one-space' Delete all but N (prefix arg) spaces. + See that command's docstring for details. +- `delete-space-after' Delete spaces after point. +- `delete-space-before' Delete spaces before point. +- `delete-all-space' Delete all spaces around point. +- `restore' Restore the original spacing. + +All those predefined actions make use of the numeric prefix arg +given to `cycle-spacing', i.e., `just-one-space' keeps this +amount of spaces deleting surplus ones. `just-one-space' and all +other actions have the contract that a positive prefix arg (or +zero) only deletes tabs and spaces whereas a negative prefix arg +also deletes newlines. + +In addition, any function which accepts one numeric argument is +allowed." + :group 'editing-basics + :type '(repeat + (choice + (const :tag "Just N (prefix arg) spaces" just-one-space) + (const :tag "Delete spaces after point" delete-space-after) + (const :tag "Delete spaces before point" delete-space-before) + (const :tag "Delete all spaces around point" delete-all-space) + (const :tag "Restore the original spacing" restore) + (function :tag "Function receiving a numerig arg"))) + :version "29.1") -(defun cycle-spacing (&optional n preserve-nl-back mode) +(defun cycle-spacing (&optional n) "Manipulate whitespace around point in a smart way. -In interactive use, this function behaves differently in successive -consecutive calls. - -The first call in a sequence acts like `just-one-space'. -It deletes all spaces and tabs around point, leaving one space -\(or N spaces). N is the prefix argument. If N is negative, -it deletes newlines as well, leaving -N spaces. -\(If PRESERVE-NL-BACK is non-nil, it does not delete newlines before point.) - -The second call in a sequence deletes all spaces. - -The third call in a sequence restores the original whitespace (and point). - -If MODE is `single-shot', it performs only the first step in the sequence. -If MODE is `fast' and the first step would not result in any change -\(i.e., there are exactly (abs N) spaces around point), -the function goes straight to the second step. - -Repeatedly calling the function with different values of N starts a -new sequence each time." +Repeated calls perform the actions in `cycle-spacing-actions' one +after the other, wrapping around after the last one. + +All actions are amendable using a prefix arg N. In general, a +zero or positive prefix arg allows only for deletion of tabs and +spaces whereas a negative prefix arg also allows for deleting +newlines. + +The prefix arg given at the first invocation starting a cycle is +provided to all following actions, i.e., + \\[negative-argument] \\[cycle-spacing] \\[cycle-spacing] \\[cycle-spacing] +is equivalent to + \\[negative-argument] \\[cycle-spacing] \\[negative-argument] \\[cycle-spacing] \\[negative-argument] \\[cycle-spacing]. + +A new sequence can be started by providing a different prefix arg +than provided at the initial invocation (except for 1), or by +doing any other command before the next \\[cycle-spacing]." (interactive "*p") - (let ((orig-pos (point)) - (skip-characters (if (and n (< n 0)) " \t\n\r" " \t")) - (num (abs (or n 1)))) - (skip-chars-backward (if preserve-nl-back " \t" skip-characters)) - (constrain-to-field nil orig-pos) - (cond - ;; Command run for the first time, single-shot mode or different argument - ((or (eq 'single-shot mode) - (not (equal last-command this-command)) - (not cycle-spacing--context) - (not (eq (car cycle-spacing--context) n))) - (let* ((start (point)) - (num (- num (skip-chars-forward " " (+ num (point))))) - (mid (point)) - (end (progn - (skip-chars-forward skip-characters) - (constrain-to-field nil orig-pos t)))) - (setq cycle-spacing--context ;; Save for later. - ;; Special handling for case where there was no space at all. - (unless (= start end) - (cons n (cons orig-pos (buffer-substring start (point)))))) - ;; If this run causes no change in buffer content, delete all spaces, - ;; otherwise delete all excess spaces. - (delete-region (if (and (eq mode 'fast) (zerop num) (= mid end)) - start mid) end) - (insert (make-string num ?\s)))) - - ;; Command run for the second time. - ((not (equal orig-pos (point))) - (delete-region (point) orig-pos)) - - ;; Command run for the third time. - (t - (insert (cddr cycle-spacing--context)) - (goto-char (cadr cycle-spacing--context)) - (setq cycle-spacing--context nil))))) + ;; Initialize `cycle-spacing--context' if needed. + (when (or (not (equal last-command this-command)) + (not cycle-spacing--context) + ;; With M-5 M-SPC M-SPC... we pass the prefix arg 5 to + ;; each action and only start a new cycle when a different + ;; prefix arg is given and which is not the default value + ;; 1. + (and (not (= n 1)) + (not (= (plist-get cycle-spacing--context :n) n)))) + (let ((orig-pos (point)) + (skip-characters " \t\n\r")) + (save-excursion + (skip-chars-backward skip-characters) + (constrain-to-field nil orig-pos) + (let ((start (point)) + (end (progn + (skip-chars-forward skip-characters) + (constrain-to-field nil orig-pos t)))) + (setq cycle-spacing--context ;; Save for later. + (list :orig-pos orig-pos + :whitespace-string (buffer-substring start end) + :n n + :last-action nil)))))) + + ;; Cycle through the actions in `cycle-spacing-actions'. + (when cycle-spacing--context + (cl-flet ((next-action () + (let* ((l cycle-spacing-actions) + (elt (plist-get cycle-spacing--context + :last-action))) + (if (null elt) + (car cycle-spacing-actions) + (catch 'found + (while l + (cond + ((null (cdr l)) + (throw 'found + (when (eq elt (car l)) + (car cycle-spacing-actions)))) + ((and (eq elt (car l)) + (cdr l)) + (throw 'found (cadr l))) + (t (setq l (cdr l))))))))) + (restore () + (delete-all-space) + (insert (plist-get cycle-spacing--context + :whitespace-string)) + (goto-char (plist-get cycle-spacing--context + :orig-pos)))) + (let ((action (next-action))) + (atomic-change-group + (restore) + (unless (eq action 'restore) + (let ((context-n (plist-get cycle-spacing--context :n))) + (cond + ((eq action 'just-one-space) + (just-one-space context-n)) + ((eq action 'delete-space-after) + (delete-region (point) + (progn + (skip-chars-forward + (if (< context-n 0) " \t\r\n" " \t")) + (constrain-to-field nil (point) t)))) + ((eq action 'delete-space-before) + (if (< context-n 0) + (delete-all-space t) + (delete-horizontal-space t))) + ((eq action 'delete-all-space) + (if (< context-n 0) + (delete-all-space) + (delete-horizontal-space))) + ((functionp action) + (funcall action context-n)) + (t + (error "Don't know how to handle action %S" action))))) + (setf (plist-get cycle-spacing--context :last-action) + action)))))) (defun beginning-of-buffer (&optional arg) "Move point to the beginning of the buffer. -- 2.36.1 --=-=-=--