unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#62892: proposal to extend mark-sexp to go forward and backward on command
@ 2023-04-17  2:25 Zachary Kanfer
  2023-04-17  3:06 ` Ruijie Yu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-04-17  7:11 ` Juri Linkov
  0 siblings, 2 replies; 43+ messages in thread
From: Zachary Kanfer @ 2023-04-17  2:25 UTC (permalink / raw)
  To: 62892


[-- Attachment #1.1: Type: text/plain, Size: 1218 bytes --]

C-M-@ is bound to `#'mark-sexp`. This command works incrementally -- that
is, calling this once marks the sexp after point; calling it again marks
one more sexp (in total, the two sexps after point).

It would be convenient to easily be able to mark sexps backwards as well.

If you've already marked sexps backwards, mark-sexp extends the region
backwards. But if you haven't, the only way to mark backwards is to pass a
negative prefix argument.

It often is a better experience to iteratively select the sexps you want.
Finally, there's no way to mark both directions, e.g., one sexp forward and
two backwards.

Attached is a patch to add #'mark-sexp-forwards and #'mark-sexp-backwards.
These functions extend the region by sexps forward and backward. They are
mutually incremental: you can call mark-sexp-fowards, then
mark-sexp-backwards twice, then mark-sexp-forwards. After this, the region
will consist of the two sexps before point and the two sexps after point.

These functions are very similar to #'mark-sexp:
- They will extend the region if it already exists.
- They can be called from lisp code with a numeric argument.
- They can take a prefix argument if called interactively.

Thanks,
Zachary Kanfer

[-- Attachment #1.2: Type: text/html, Size: 1356 bytes --]

[-- Attachment #2: 0001-Add-mark-sexp-forward-mark-sexp-backward.patch --]
[-- Type: text/x-patch, Size: 2967 bytes --]

From 3a35790a79eff3d597e13a17d740357bc556d81e Mon Sep 17 00:00:00 2001
From: Zachary Kanfer <zkanfer@gmail.com>
Date: Sun, 16 Apr 2023 22:16:39 -0400
Subject: [PATCH] Add mark-sexp-forward, mark-sexp-backward

---
 etc/NEWS                |  4 ++++
 lisp/emacs-lisp/lisp.el | 41 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 45 insertions(+)

diff --git a/etc/NEWS b/etc/NEWS
index c61a9ec3c5f..9f2b7d21f9b 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -81,6 +81,10 @@ mistaken compositions, this will now work as well.
 This works like 'kill-matching-buffers', but without asking for
 confirmation.
 
+---
+** New commands 'mark-sexp-forward' and 'mark-sexp-backward'.
+These work like mark-sexp, but explicitly allow sexps to be marked forward and backward.
+
 \f
 * Changes in Specialized Modes and Packages in Emacs 30.1
 
diff --git a/lisp/emacs-lisp/lisp.el b/lisp/emacs-lisp/lisp.el
index 417c218c6d7..d6649b2497d 100644
--- a/lisp/emacs-lisp/lisp.el
+++ b/lisp/emacs-lisp/lisp.el
@@ -129,6 +129,47 @@ mark-sexp
 	    (point))
 	  nil t))))
 
+(defun mark-sexp-helper (number-of-expressions)
+  "A helper function for 'mark-sexp-[forward, backward]'.
+
+If NUMBER-OF-EXPRESSIONS is positive, mark that many sexps forward;
+otherwise, amrk backward."
+  (if (use-region-p)
+      (let* ((forward (>= number-of-expressions 0))
+             (beginning-of-region (region-beginning))
+             (end-of-region (region-end))
+             (at-end-of-region (= end-of-region (point)))
+             (new-border-point
+              (save-excursion
+                (goto-char (if forward (region-end) (region-beginning)))
+                (condition-case nil
+                    (forward-sexp number-of-expressions)
+                  (scan-error (user-error "No more s-expressions there!")))
+                (point)))
+             (new-beginning-of-region (min beginning-of-region new-border-point))
+             (new-end-of-region (max end-of-region new-border-point)))
+        (goto-char (if at-end-of-region
+                       new-end-of-region
+                     new-beginning-of-region))
+        (set-mark (if at-end-of-region
+                      new-beginning-of-region
+                    new-end-of-region)))
+    (mark-sexp number-of-expressions)))
+
+(defun mark-sexp-forward (&optional number-of-expressions)
+  "Mark NUMBER-OF-EXPRESSIONS s-expressions forward.
+
+ Repeated calls to this mark more s-expressions."
+  (interactive "p")
+  (mark-sexp-helper (or number-of-expressions 1)))
+
+(defun mark-sexp-backward (&optional number-of-expressions)
+  "Mark NUMBER-OF-EXPRESSIONS s-expressions backward.
+
+ Repeated calls to this mark more s-expressions."
+  (interactive "p")
+  (mark-sexp-helper (- (or number-of-expressions 1))))
+
 (defun forward-list (&optional arg interactive)
   "Move forward across one balanced group of parentheses.
 This command will also work on other parentheses-like expressions
-- 
2.38.4


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* bug#62892: proposal to extend mark-sexp to go forward and backward on command
  2023-04-17  2:25 bug#62892: proposal to extend mark-sexp to go forward and backward on command Zachary Kanfer
@ 2023-04-17  3:06 ` Ruijie Yu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-04-20  5:25   ` Zachary Kanfer
  2023-04-21 13:10   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-04-17  7:11 ` Juri Linkov
  1 sibling, 2 replies; 43+ messages in thread
From: Ruijie Yu via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-04-17  3:06 UTC (permalink / raw)
  To: Zachary Kanfer; +Cc: 62892


Zachary Kanfer <zkanfer@gmail.com> writes:

> Attached is a patch to add #'mark-sexp-forwards and #'mark-sexp-backwards. These functions extend the region by sexps forward and
> backward. They are mutually incremental: you can call mark-sexp-fowards, then mark-sexp-backwards twice, then mark-sexp-forwards. After
> this, the region will consist of the two sexps before point and the two sexps after point.

If this is to be accepted, why not extend it to all like mark functions,
listed below?  Implementing them should be pretty similar, and you might
even be able to reuse the same helper for all these variants.  Also, the
helper function might need to contain a double-dash in its name because
this is inherently a private function.

- `mark-defun'
- `mark-page'
- `mark-paragraph'
- `mark-word'

> +(defun mark-sexp-helper (number-of-expressions)
> +  "A helper function for 'mark-sexp-[forward, backward]'.
> +
> +If NUMBER-OF-EXPRESSIONS is positive, mark that many sexps forward;
> +otherwise, amrk backward."

Please use `quote' to quote things in Emacs docstrings.  Also, both here
and in other docstrings, the newline immediately after the first line,
while seems necessary, is usually redundant in Emacs docstrings.  And
there is a typo: "amrk" -> "mark".

I also think you shouldn't use wildcard-like elements in quotes (in your
case, you reuse part of the name in the quote), but I'm not sure.

-- 
Best,


RY





^ permalink raw reply	[flat|nested] 43+ messages in thread

* bug#62892: proposal to extend mark-sexp to go forward and backward on command
  2023-04-17  2:25 bug#62892: proposal to extend mark-sexp to go forward and backward on command Zachary Kanfer
  2023-04-17  3:06 ` Ruijie Yu via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2023-04-17  7:11 ` Juri Linkov
  1 sibling, 0 replies; 43+ messages in thread
From: Juri Linkov @ 2023-04-17  7:11 UTC (permalink / raw)
  To: Zachary Kanfer; +Cc: 62892

> C-M-@ is bound to `#'mark-sexp`. This command works incrementally -- that
> is, calling this once marks the sexp after point; calling it again marks
> one more sexp (in total, the two sexps after point).
>
> It would be convenient to easily be able to mark sexps backwards as well.

Did you know that it's possible to switch directions by typing 'C-x C-x'.
After that 'C-M-@' extends the region backwards.





^ permalink raw reply	[flat|nested] 43+ messages in thread

* bug#62892: proposal to extend mark-sexp to go forward and backward on command
  2023-04-17  3:06 ` Ruijie Yu via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2023-04-20  5:25   ` Zachary Kanfer
  2023-04-20  7:16     ` Eli Zaretskii
  2023-04-21 13:10   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  1 sibling, 1 reply; 43+ messages in thread
From: Zachary Kanfer @ 2023-04-20  5:25 UTC (permalink / raw)
  To: Ruijie Yu; +Cc: 62892


[-- Attachment #1.1: Type: text/plain, Size: 2565 bytes --]

> If this is to be accepted, why not extend it to all like mark functions,
> listed below?  Implementing them should be pretty similar, and you might
> even be able to reuse the same helper for all these variants.  Also, the
> helper function might need to contain a double-dash in its name because
> this is inherently a private function.

This makes sense to me, although I have not found the same need for these
to be marked. I'm happy to extend them as such; I'll add that in a later
patch.

> Please use `quote' to quote things in Emacs docstrings.  Also, both here
> and in other docstrings, the newline immediately after the first line,
> while seems necessary, is usually redundant in Emacs docstrings.  And
> there is a typo: "amrk" -> "mark".
>
> I also think you shouldn't use wildcard-like elements in quotes (in your
> case, you reuse part of the name in the quote), but I'm not sure.

Done. Updated patch attached.

On Sun, Apr 16, 2023 at 11:17 PM Ruijie Yu <ruijie@netyu.xyz> wrote:

>
> Zachary Kanfer <zkanfer@gmail.com> writes:
>
> > Attached is a patch to add #'mark-sexp-forwards and
> #'mark-sexp-backwards. These functions extend the region by sexps forward
> and
> > backward. They are mutually incremental: you can call mark-sexp-fowards,
> then mark-sexp-backwards twice, then mark-sexp-forwards. After
> > this, the region will consist of the two sexps before point and the two
> sexps after point.
>
> If this is to be accepted, why not extend it to all like mark functions,
> listed below?  Implementing them should be pretty similar, and you might
> even be able to reuse the same helper for all these variants.  Also, the
> helper function might need to contain a double-dash in its name because
> this is inherently a private function.
>
> - `mark-defun'
> - `mark-page'
> - `mark-paragraph'
> - `mark-word'
>
> > +(defun mark-sexp-helper (number-of-expressions)
> > +  "A helper function for 'mark-sexp-[forward, backward]'.
> > +
> > +If NUMBER-OF-EXPRESSIONS is positive, mark that many sexps forward;
> > +otherwise, amrk backward."
>
> Please use `quote' to quote things in Emacs docstrings.  Also, both here
> and in other docstrings, the newline immediately after the first line,
> while seems necessary, is usually redundant in Emacs docstrings.  And
> there is a typo: "amrk" -> "mark".
>
> I also think you shouldn't use wildcard-like elements in quotes (in your
> case, you reuse part of the name in the quote), but I'm not sure.
>
> --
> Best,
>
>
> RY
>

[-- Attachment #1.2: Type: text/html, Size: 3323 bytes --]

[-- Attachment #2: 0001-Add-mark-sexp-forward-mark-sexp-backward.patch --]
[-- Type: text/x-patch, Size: 2980 bytes --]

From 5b33520a73a8f116fb89ba253f6636c9573c9d2f Mon Sep 17 00:00:00 2001
From: Zachary Kanfer <zkanfer@gmail.com>
Date: Sun, 16 Apr 2023 22:16:39 -0400
Subject: [PATCH] Add mark-sexp-forward, mark-sexp-backward

---
 etc/NEWS                |  4 ++++
 lisp/emacs-lisp/lisp.el | 41 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 45 insertions(+)

diff --git a/etc/NEWS b/etc/NEWS
index c61a9ec3c5f..9f2b7d21f9b 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -81,6 +81,10 @@ mistaken compositions, this will now work as well.
 This works like 'kill-matching-buffers', but without asking for
 confirmation.
 
+---
+** New commands 'mark-sexp-forward' and 'mark-sexp-backward'.
+These work like mark-sexp, but explicitly allow sexps to be marked forward and backward.
+
 \f
 * Changes in Specialized Modes and Packages in Emacs 30.1
 
diff --git a/lisp/emacs-lisp/lisp.el b/lisp/emacs-lisp/lisp.el
index 417c218c6d7..cdd9459c436 100644
--- a/lisp/emacs-lisp/lisp.el
+++ b/lisp/emacs-lisp/lisp.el
@@ -129,6 +129,47 @@ mark-sexp
 	    (point))
 	  nil t))))
 
+(defun mark-sexp--helper (number-of-expressions)
+  "A helper function for `mark-sexp-forward', `mark-sexp-backward'.
+
+If NUMBER-OF-EXPRESSIONS is positive, mark that many sexps forward;
+otherwise, mark backward."
+  (if (use-region-p)
+      (let* ((forward (>= number-of-expressions 0))
+             (beginning-of-region (region-beginning))
+             (end-of-region (region-end))
+             (at-end-of-region (= end-of-region (point)))
+             (new-border-point
+              (save-excursion
+                (goto-char (if forward (region-end) (region-beginning)))
+                (condition-case nil
+                    (forward-sexp number-of-expressions)
+                  (scan-error (user-error "No more s-expressions there!")))
+                (point)))
+             (new-beginning-of-region (min beginning-of-region new-border-point))
+             (new-end-of-region (max end-of-region new-border-point)))
+        (goto-char (if at-end-of-region
+                       new-end-of-region
+                     new-beginning-of-region))
+        (set-mark (if at-end-of-region
+                      new-beginning-of-region
+                    new-end-of-region)))
+    (mark-sexp number-of-expressions)))
+
+(defun mark-sexp-forward (&optional number-of-expressions)
+  "Mark NUMBER-OF-EXPRESSIONS s-expressions forward.
+
+ Repeated calls to this mark more s-expressions."
+  (interactive "p")
+  (mark-sexp--helper (or number-of-expressions 1)))
+
+(defun mark-sexp-backward (&optional number-of-expressions)
+  "Mark NUMBER-OF-EXPRESSIONS s-expressions backward.
+
+ Repeated calls to this mark more s-expressions."
+  (interactive "p")
+  (mark-sexp--helper (- (or number-of-expressions 1))))
+
 (defun forward-list (&optional arg interactive)
   "Move forward across one balanced group of parentheses.
 This command will also work on other parentheses-like expressions
-- 
2.38.4


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* bug#62892: proposal to extend mark-sexp to go forward and backward on command
  2023-04-20  5:25   ` Zachary Kanfer
@ 2023-04-20  7:16     ` Eli Zaretskii
  2023-04-21  5:04       ` Zachary Kanfer
  0 siblings, 1 reply; 43+ messages in thread
From: Eli Zaretskii @ 2023-04-20  7:16 UTC (permalink / raw)
  To: Zachary Kanfer; +Cc: ruijie, 62892, Juri Linkov

> Cc: 62892@debbugs.gnu.org
> From: Zachary Kanfer <zkanfer@gmail.com>
> Date: Thu, 20 Apr 2023 01:25:29 -0400
> 
> > If this is to be accepted, why not extend it to all like mark functions,
> > listed below?  Implementing them should be pretty similar, and you might
> > even be able to reuse the same helper for all these variants.  Also, the
> > helper function might need to contain a double-dash in its name because
> > this is inherently a private function.
> 
> This makes sense to me, although I have not found the same need for these to be marked. I'm happy
> to extend them as such; I'll add that in a later patch.
> 
> > Please use `quote' to quote things in Emacs docstrings.  Also, both here
> > and in other docstrings, the newline immediately after the first line,
> > while seems necessary, is usually redundant in Emacs docstrings.  And
> > there is a typo: "amrk" -> "mark".
> > 
> > I also think you shouldn't use wildcard-like elements in quotes (in your
> > case, you reuse part of the name in the quote), but I'm not sure.
> 
> Done. Updated patch attached.

Thanks.

Did you see the comment by Juri, viz.:

> Did you know that it's possible to switch directions by typing 'C-x C-x'.
> After that 'C-M-@' extends the region backwards.

AFAIU, this means we already have an easy method to have C-M-@ switch
directions, and the changes you propose might therefore be
unnecessary.  WDYT?





^ permalink raw reply	[flat|nested] 43+ messages in thread

* bug#62892: proposal to extend mark-sexp to go forward and backward on command
  2023-04-20  7:16     ` Eli Zaretskii
@ 2023-04-21  5:04       ` Zachary Kanfer
  2023-04-21  6:07         ` Eli Zaretskii
  0 siblings, 1 reply; 43+ messages in thread
From: Zachary Kanfer @ 2023-04-21  5:04 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: ruijie, 62892, Juri Linkov

[-- Attachment #1: Type: text/plain, Size: 2176 bytes --]

It's able to be worked around, yes -- but I think it's easier to have
separate methods for forward and backward, the way we do for so many other
commands. For one, having separate functions makes it easier to start
moving backward, (rather than giving a -1 prefix argument.

It's especially useful, I think, because on default Emacs, both C-M-SPC and
C-M-S-SPC are bound to mark-sexp; it's quite nice to have C-M-SPC bound to
mark-sexp-forward and C-M-S-SPC bound to mark-sexp-backward. So there are
seemingly obvious keybindings to use for it (even if not in stock Emacs).

On Thu, Apr 20, 2023 at 3:16 AM Eli Zaretskii <eliz@gnu.org> wrote:

> > Cc: 62892@debbugs.gnu.org
> > From: Zachary Kanfer <zkanfer@gmail.com>
> > Date: Thu, 20 Apr 2023 01:25:29 -0400
> >
> > > If this is to be accepted, why not extend it to all like mark
> functions,
> > > listed below?  Implementing them should be pretty similar, and you
> might
> > > even be able to reuse the same helper for all these variants.  Also,
> the
> > > helper function might need to contain a double-dash in its name because
> > > this is inherently a private function.
> >
> > This makes sense to me, although I have not found the same need for
> these to be marked. I'm happy
> > to extend them as such; I'll add that in a later patch.
> >
> > > Please use `quote' to quote things in Emacs docstrings.  Also, both
> here
> > > and in other docstrings, the newline immediately after the first line,
> > > while seems necessary, is usually redundant in Emacs docstrings.  And
> > > there is a typo: "amrk" -> "mark".
> > >
> > > I also think you shouldn't use wildcard-like elements in quotes (in
> your
> > > case, you reuse part of the name in the quote), but I'm not sure.
> >
> > Done. Updated patch attached.
>
> Thanks.
>
> Did you see the comment by Juri, viz.:
>
> > Did you know that it's possible to switch directions by typing 'C-x C-x'.
> > After that 'C-M-@' extends the region backwards.
>
> AFAIU, this means we already have an easy method to have C-M-@ switch
> directions, and the changes you propose might therefore be
> unnecessary.  WDYT?
>

[-- Attachment #2: Type: text/html, Size: 2845 bytes --]

^ permalink raw reply	[flat|nested] 43+ messages in thread

* bug#62892: proposal to extend mark-sexp to go forward and backward on command
  2023-04-21  5:04       ` Zachary Kanfer
@ 2023-04-21  6:07         ` Eli Zaretskii
  2023-04-21  7:24           ` Eshel Yaron via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-04-21  9:51           ` Visuwesh
  0 siblings, 2 replies; 43+ messages in thread
From: Eli Zaretskii @ 2023-04-21  6:07 UTC (permalink / raw)
  To: Zachary Kanfer, Stefan Monnier, Lars Ingebrigtsen; +Cc: ruijie, 62892, juri

> From: Zachary Kanfer <zkanfer@gmail.com>
> Date: Fri, 21 Apr 2023 01:04:30 -0400
> Cc: ruijie@netyu.xyz, 62892@debbugs.gnu.org, Juri Linkov <juri@linkov.net>
> 
> It's able to be worked around, yes -- but I think it's easier to have separate methods for forward and
> backward, the way we do for so many other commands. For one, having separate functions makes it
> easier to start moving backward, (rather than giving a -1 prefix argument.

Adding functions and commands is not free, it does come with a price:
they need to be documented in our two manuals (something your patch
neglected to do, btw), users need to learn them, etc.

So I wonder whether on balance it is justified to add this.  Lars,
Stefan: any comments or opinions?

Does anyone else have an opinion?





^ permalink raw reply	[flat|nested] 43+ messages in thread

* bug#62892: proposal to extend mark-sexp to go forward and backward on command
  2023-04-21  6:07         ` Eli Zaretskii
@ 2023-04-21  7:24           ` Eshel Yaron via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-04-21  9:51           ` Visuwesh
  1 sibling, 0 replies; 43+ messages in thread
From: Eshel Yaron via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-04-21  7:24 UTC (permalink / raw)
  To: Eli Zaretskii
  Cc: Zachary Kanfer, juri, ruijie, Stefan Monnier, Lars Ingebrigtsen,
	62892

Eli Zaretskii <eliz@gnu.org> writes:

>> From: Zachary Kanfer <zkanfer@gmail.com>
>> Date: Fri, 21 Apr 2023 01:04:30 -0400
>> Cc: ruijie@netyu.xyz, 62892@debbugs.gnu.org, Juri Linkov <juri@linkov.net>
>> 
>> It's able to be worked around, yes -- but I think it's easier to have separate methods for forward and
>> backward, the way we do for so many other commands. For one, having separate functions makes it
>> easier to start moving backward, (rather than giving a -1 prefix argument.
>
> Adding functions and commands is not free, it does come with a price:
> they need to be documented in our two manuals (something your patch
> neglected to do, btw), users need to learn them, etc.
>
> So I wonder whether on balance it is justified to add this.  Lars,
> Stefan: any comments or opinions?
>
> Does anyone else have an opinion?

Not really a strong opinion, but just a couple of thoughts:

- The ability to extend the selection forward and backward is a nice and
desirable feature.

- C-x C-x is a general mechanism that's useful in many situations and
users are hopefully already familiar with it (although not necessarily
aware of this specific use case, I wasn't!), so if it fits the bill it
makes sense to reuse it rather than introducing new specialized commands.

- Whatever decision is made with regards to mark-sexp, I think it should
be consistent with similar marking commands.  Notably, mark-word
currently behaves like mark-sexp, and I think that adding e.g.
mark-sexp-backward without also adding mark-word-backward would somewhat
hinder consistency.

Regards,
Eshel






^ permalink raw reply	[flat|nested] 43+ messages in thread

* bug#62892: proposal to extend mark-sexp to go forward and backward on command
  2023-04-21  6:07         ` Eli Zaretskii
  2023-04-21  7:24           ` Eshel Yaron via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2023-04-21  9:51           ` Visuwesh
  1 sibling, 0 replies; 43+ messages in thread
From: Visuwesh @ 2023-04-21  9:51 UTC (permalink / raw)
  To: Eli Zaretskii
  Cc: Zachary Kanfer, juri, ruijie, Stefan Monnier, Lars Ingebrigtsen,
	62892

[வெள்ளி ஏப்ரல் 21, 2023] Eli Zaretskii wrote:

>> From: Zachary Kanfer <zkanfer@gmail.com>
>> Date: Fri, 21 Apr 2023 01:04:30 -0400
>> Cc: ruijie@netyu.xyz, 62892@debbugs.gnu.org, Juri Linkov <juri@linkov.net>
>> 
>> It's able to be worked around, yes -- but I think it's easier to have separate methods for forward and
>> backward, the way we do for so many other commands. For one, having separate functions makes it
>> easier to start moving backward, (rather than giving a -1 prefix argument.
>
> Adding functions and commands is not free, it does come with a price:
> they need to be documented in our two manuals (something your patch
> neglected to do, btw), users need to learn them, etc.
>
> So I wonder whether on balance it is justified to add this.  Lars,
> Stefan: any comments or opinions?
>
> Does anyone else have an opinion?

In situations like these, I extend the region simply by motion commands
after marking the current sexp.  If I want to go in the opposite
direction, I type C-x C-x.  I don't see myself ever using these
commands.
This mechanism works for every object that has a mark command, not just
sexp which I consider a plus.





^ permalink raw reply	[flat|nested] 43+ messages in thread

* bug#62892: proposal to extend mark-sexp to go forward and backward on command
  2023-04-17  3:06 ` Ruijie Yu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-04-20  5:25   ` Zachary Kanfer
@ 2023-04-21 13:10   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-04-23  5:33     ` Zachary Kanfer
  1 sibling, 1 reply; 43+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-04-21 13:10 UTC (permalink / raw)
  To: Ruijie Yu; +Cc: Zachary Kanfer, 62892

> If this is to be accepted, why not extend it to all like mark functions,
> listed below?  Implementing them should be pretty similar, and you might
> even be able to reuse the same helper for all these variants.  Also, the
> helper function might need to contain a double-dash in its name because
> this is inherently a private function.
>
> - `mark-defun'
> - `mark-page'
> - `mark-paragraph'
> - `mark-word'

Agreed: we should move towards a more orthogonal/composable design,
where the granularity of the operation (char, word, line, sexp,
paragraph, page, defun, ...) and the operation itself (move, mark) and
the direction and all independent such that we can use any combination
of them.

Both at the ELisp level and at the key-binding level.


        Stefan






^ permalink raw reply	[flat|nested] 43+ messages in thread

* bug#62892: proposal to extend mark-sexp to go forward and backward on command
  2023-04-21 13:10   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2023-04-23  5:33     ` Zachary Kanfer
  2023-04-25 22:26       ` Daniel Martín via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-04-28 17:04       ` Juri Linkov
  0 siblings, 2 replies; 43+ messages in thread
From: Zachary Kanfer @ 2023-04-23  5:33 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Ruijie Yu, 62892


[-- Attachment #1.1: Type: text/plain, Size: 2654 bytes --]

Attached is a patch with a few updates:

1. Added documentation in doc/emacs/mark.texi, under the mark-sexp section.
I'm unfamiliar with standards for how the manuals are written, but am happy
to update further as needed.
2. Extracted a new helper function mark--helper. This takes two arguments
-- a move function, and a number of how many things to move.

The helper function is able to be used for all mark-*-forward and
mark-*-backward functions; I think this should handle at least some of your
concerns about the composability of the design -- different mark functions
can be made by passing a different move function. For example,
mark-word-forward and mark-word-backward would be defined this way:

(defun mark-word-forward (&optional number-of-words)
  "Mark NUMBER-OF-WORDS words forward.

 Repeated calls to this mark more words."
  (interactive "p")
  (mark--helper #'forward-word (or number-of-words 1)))

(defun mark-word-backward (&optional number-of-words)
  "Mark NUMBER-OF-WORDS words backward.

 Repeated calls to this mark more words."
  (interactive "p")
  (mark--helper #'forward-word (- (or number-of-words 1))))

I'm not exactly sure of the best place to put the helper function, nor
exactly how the different lisp files in Emacs work together. There's no
provide statement; are all the files in lisp/emacs-lisp loaded at the same
time? If so, I'll make the other relevant functions (for marking word,
defun, page, paragraph, line, and char).

Also, whatever the outcome of this patch, I think it would be advisable to
explain somewhere how mark-sexp extends region by the end of region
opposite point; this is not in the docstring or any other documentation
I've seen.

On Fri, Apr 21, 2023 at 9:10 AM Stefan Monnier <monnier@iro.umontreal.ca>
wrote:

> > If this is to be accepted, why not extend it to all like mark functions,
> > listed below?  Implementing them should be pretty similar, and you might
> > even be able to reuse the same helper for all these variants.  Also, the
> > helper function might need to contain a double-dash in its name because
> > this is inherently a private function.
> >
> > - `mark-defun'
> > - `mark-page'
> > - `mark-paragraph'
> > - `mark-word'
>
> Agreed: we should move towards a more orthogonal/composable design,
> where the granularity of the operation (char, word, line, sexp,
> paragraph, page, defun, ...) and the operation itself (move, mark) and
> the direction and all independent such that we can use any combination
> of them.
>
> Both at the ELisp level and at the key-binding level.
>
>
>         Stefan
>
>

[-- Attachment #1.2: Type: text/html, Size: 3252 bytes --]

[-- Attachment #2: 0001-Add-mark-sexp-forward-mark-sexp-backward.patch --]
[-- Type: text/x-patch, Size: 3983 bytes --]

From ec5fb0b09dc05d5726874c316de0028a9a4c46b3 Mon Sep 17 00:00:00 2001
From: Zachary Kanfer <zkanfer@gmail.com>
Date: Sun, 16 Apr 2023 22:16:39 -0400
Subject: [PATCH] Add mark-sexp-forward, mark-sexp-backward

---
 doc/emacs/mark.texi     |  8 +++++++
 etc/NEWS                |  4 ++++
 lisp/emacs-lisp/lisp.el | 46 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 58 insertions(+)

diff --git a/doc/emacs/mark.texi b/doc/emacs/mark.texi
index 3f1c76c1591..9c230a72252 100644
--- a/doc/emacs/mark.texi
+++ b/doc/emacs/mark.texi
@@ -224,6 +224,14 @@ Marking Objects
 positive or negative numeric arguments move the mark forward or
 backward by the specified number of expressions.
 
+@findex mark-sexp-forward
+  @code{mark-sexp-forward} is similar to @code{mark-sexp}, but only
+  moves forward.
+
+@findex mark-sexp-backward
+  @code{mark-sexp-backward} is similar to @code{mark-sexp}, but only
+  moves backward.
+
    The other commands in the above list set both point and mark, so as
 to delimit an object in the buffer.  @kbd{M-h} (@code{mark-paragraph})
 marks paragraphs (@pxref{Paragraphs}), @kbd{C-M-h} (@code{mark-defun})
diff --git a/etc/NEWS b/etc/NEWS
index c61a9ec3c5f..9f2b7d21f9b 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -81,6 +81,10 @@ mistaken compositions, this will now work as well.
 This works like 'kill-matching-buffers', but without asking for
 confirmation.
 
+---
+** New commands 'mark-sexp-forward' and 'mark-sexp-backward'.
+These work like mark-sexp, but explicitly allow sexps to be marked forward and backward.
+
 \f
 * Changes in Specialized Modes and Packages in Emacs 30.1
 
diff --git a/lisp/emacs-lisp/lisp.el b/lisp/emacs-lisp/lisp.el
index 417c218c6d7..30194354f19 100644
--- a/lisp/emacs-lisp/lisp.el
+++ b/lisp/emacs-lisp/lisp.el
@@ -129,6 +129,52 @@ mark-sexp
 	    (point))
 	  nil t))))
 
+(defun mark--helper (move-fn number-of-things)
+  "Use MOVE-FN to move NUMBER-OF-THINGS things, extending region over them.
+
+The MOVE-FN should take a numeric argument, and move that many
+items forward (negative means backward).
+
+NUMBER-OF-THINGS is the number of additional things to move."
+  (if (use-region-p)
+      (let* ((forward (>= number-of-things 0))
+             (beginning-of-region (region-beginning))
+             (end-of-region (region-end))
+             (at-end-of-region (= end-of-region (point)))
+             (new-border-point
+              (save-excursion
+                (goto-char (if forward (region-end) (region-beginning)))
+                (condition-case nil
+                    (funcall move-fn number-of-things)
+                  (scan-error (user-error "No more in this direction!")))
+                (point)))
+             (new-beginning-of-region (min beginning-of-region new-border-point))
+             (new-end-of-region (max end-of-region new-border-point)))
+        (goto-char (if at-end-of-region
+                       new-end-of-region
+                     new-beginning-of-region))
+        (set-mark (if at-end-of-region
+                      new-beginning-of-region
+                    new-end-of-region)))
+    (progn (push-mark (save-excursion
+                        (funcall move-fn number-of-things)
+                        (point)))
+           (activate-mark))))
+
+(defun mark-sexp-forward (&optional number-of-expressions)
+  "Mark NUMBER-OF-EXPRESSIONS s-expressions forward.
+
+ Repeated calls to this mark more s-expressions."
+  (interactive "p")
+  (mark--helper #'forward-sexp (or number-of-expressions 1)))
+
+(defun mark-sexp-backward (&optional number-of-expressions)
+  "Mark NUMBER-OF-EXPRESSIONS s-expressions backward.
+
+ Repeated calls to this mark more s-expressions."
+  (interactive "p")
+  (mark--helper #'forward-sexp (- (or number-of-expressions 1))))
+
 (defun forward-list (&optional arg interactive)
   "Move forward across one balanced group of parentheses.
 This command will also work on other parentheses-like expressions
-- 
2.38.4


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* bug#62892: proposal to extend mark-sexp to go forward and backward on command
  2023-04-23  5:33     ` Zachary Kanfer
@ 2023-04-25 22:26       ` Daniel Martín via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-04-26  4:41         ` Zachary Kanfer
  2023-04-28 17:04       ` Juri Linkov
  1 sibling, 1 reply; 43+ messages in thread
From: Daniel Martín via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-04-25 22:26 UTC (permalink / raw)
  To: Zachary Kanfer; +Cc: Ruijie Yu, Stefan Monnier, 62892

Zachary Kanfer <zkanfer@gmail.com> writes:

>
> Also, whatever the outcome of this patch, I think it would be advisable to
> explain somewhere how mark-sexp extends region by the end of region
> opposite point; this is not in the docstring or any other documentation
> I've seen.
>

In my opinion, the description of that feature should not be part of the
mark-sexp command documentation, because the feature is actually
provided by C-x C-x (exchange-point-and-mark).  The Emacs manual in
section 12.1 Setting the Mark describes this use case well, I think:

‘C-x C-x’ is useful when you are
satisfied with the position of point but want to move the other end of
the region (where the mark is).





^ permalink raw reply	[flat|nested] 43+ messages in thread

* bug#62892: proposal to extend mark-sexp to go forward and backward on command
  2023-04-25 22:26       ` Daniel Martín via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2023-04-26  4:41         ` Zachary Kanfer
  2023-04-26  6:28           ` Eli Zaretskii
  0 siblings, 1 reply; 43+ messages in thread
From: Zachary Kanfer @ 2023-04-26  4:41 UTC (permalink / raw)
  To: Daniel Martín; +Cc: Ruijie Yu, Stefan Monnier, 62892

[-- Attachment #1: Type: text/plain, Size: 1911 bytes --]

The documentation for mark-sexp says:

> Set mark ARG sexps from point.
> The place mark goes is the same place C-M-<right> would
> move to with the same argument.

This is correct but misleading. Worse still is the next part:

> Interactively, if this command is repeated
> or (in Transient Mark mode) if the mark is active,
> it marks the next ARG sexps after the ones already marked.

This says it marks sexps *after* the ones already marked. This is
incorrect; if point is *after* mark, and mark is active, this function
marks sexps *before* the ones already marked.

> In my opinion, the description of that feature should not be part of the
> mark-sexp command documentation, because the feature is actually
> provided by C-x C-x (exchange-point-and-mark).

One way for this situation to occur is by using C-x C-x, yes, but it's not
the only way. You can set point, move forward sexps, and then calling
mark-sexp will mark sexps backwards.

There is specific code in mark-sexp to check which direction to move; it
should be documented as such.

On Tue, Apr 25, 2023 at 6:26 PM Daniel Martín <mardani29@yahoo.es> wrote:

> Zachary Kanfer <zkanfer@gmail.com> writes:
>
> >
> > Also, whatever the outcome of this patch, I think it would be advisable
> to
> > explain somewhere how mark-sexp extends region by the end of region
> > opposite point; this is not in the docstring or any other documentation
> > I've seen.
> >
>
> In my opinion, the description of that feature should not be part of the
> mark-sexp command documentation, because the feature is actually
> provided by C-x C-x (exchange-point-and-mark).  The Emacs manual in
> section 12.1 Setting the Mark describes this use case well, I think:
>
> ‘C-x C-x’ is useful when you are
> satisfied with the position of point but want to move the other end of
> the region (where the mark is).
>

[-- Attachment #2: Type: text/html, Size: 2524 bytes --]

^ permalink raw reply	[flat|nested] 43+ messages in thread

* bug#62892: proposal to extend mark-sexp to go forward and backward on command
  2023-04-26  4:41         ` Zachary Kanfer
@ 2023-04-26  6:28           ` Eli Zaretskii
  2023-04-27  2:37             ` Zachary Kanfer
  0 siblings, 1 reply; 43+ messages in thread
From: Eli Zaretskii @ 2023-04-26  6:28 UTC (permalink / raw)
  To: Zachary Kanfer; +Cc: ruijie, monnier, 62892, mardani29

> Cc: Ruijie Yu <ruijie@netyu.xyz>, Stefan Monnier <monnier@iro.umontreal.ca>,
>  62892@debbugs.gnu.org
> From: Zachary Kanfer <zkanfer@gmail.com>
> Date: Wed, 26 Apr 2023 00:41:45 -0400
> 
> The documentation for mark-sexp says:
> 
> > Set mark ARG sexps from point.
> > The place mark goes is the same place C-M-<right> would
> > move to with the same argument.
> 
> This is correct but misleading.

Please elaborate: how could it mislead?

> Worse still is the next part:
> 
> > Interactively, if this command is repeated
> > or (in Transient Mark mode) if the mark is active,
> > it marks the next ARG sexps after the ones already marked.
> 
> This says it marks sexps *after* the ones already marked. This is incorrect; if point is *after* mark, and
> mark is active, this function marks sexps *before* the ones already marked.

I cannot reproduce this behavior, if I understand your description
correctly.  Please show a recipe, starting from "emacs -Q", to
reproduce.

> > In my opinion, the description of that feature should not be part of the
> > mark-sexp command documentation, because the feature is actually
> > provided by C-x C-x (exchange-point-and-mark).
> 
> One way for this situation to occur is by using C-x C-x, yes, but it's not the only way. You can set point,
> move forward sexps, and then calling mark-sexp will mark sexps backwards.
> 
> There is specific code in mark-sexp to check which direction to move; it should be documented as
> such.

Please also demonstrate this behavior and point to that code, so we
will know what you are alluding to.

Thanks.





^ permalink raw reply	[flat|nested] 43+ messages in thread

* bug#62892: proposal to extend mark-sexp to go forward and backward on command
  2023-04-26  6:28           ` Eli Zaretskii
@ 2023-04-27  2:37             ` Zachary Kanfer
  2023-04-27 12:25               ` Eli Zaretskii
  0 siblings, 1 reply; 43+ messages in thread
From: Zachary Kanfer @ 2023-04-27  2:37 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: ruijie, monnier, 62892, mardani29

[-- Attachment #1: Type: text/plain, Size: 5324 bytes --]

> > Worse still is the next part:
> >
> > > Interactively, if this command is repeated
> > > or (in Transient Mark mode) if the mark is active,
> > > it marks the next ARG sexps after the ones already marked.
> >
> > This says it marks sexps *after* the ones already marked. This is
incorrect; if point is *after* mark, and
> > mark is active, this function marks sexps *before* the ones already
marked.
>
> I cannot reproduce this behavior, if I understand your description
> correctly.  Please show a recipe, starting from "emacs -Q", to
> reproduce.

Open Emacs with:

emacs -Q --eval '(progn (insert "foo bar baz") (goto-char 8) (set-mark 5))'

It will insert "foo bar baz", put point after "bar", and mark before "bar".
Region contains "bar".

Then when we run mark-sexp, we expect to mark some sexps "after the ones
already marked". That's what the docstring says.

After running the command above to open emacs, press C-M-@ to run
mark-sexp. We should see sexps marked "after the ones already marked"; that
is, we should see "bar baz" marked. But we don't. Instead, we see that "foo
bar" is highlighted. That is, we have marked sexps *before* the ones
already marked.


> > The documentation for mark-sexp says:
> >
> > > Set mark ARG sexps from point.
> > > The place mark goes is the same place C-M-<right> would
> > > move to with the same argument.
> >
> > This is correct but misleading.
>
> Please elaborate: how could it mislead?

"The same argument" is the misleading part. If I call mark-sexp with no
argument, sometimes that code passes -1 to forward-sexp. So while I think
I'm effectively passing a "1" to mark-sexp, instead -1 is passed to
forward-sexp. This is somewhat explained by the next part of the docstring,
but not entirely. Read with the rest of the docstring, it reinforces the
belief that the command only marks sexps *after* point.

> > > In my opinion, the description of that feature should not be part of
the
> > > mark-sexp command documentation, because the feature is actually
> > > provided by C-x C-x (exchange-point-and-mark).
> >
> > One way for this situation to occur is by using C-x C-x, yes, but it's
not the only way. You can set point,
> > move forward sexps, and then calling mark-sexp will mark sexps
backwards.
> >
> > There is specific code in mark-sexp to check which direction to move;
it should be documented as
> > such.
>
> Please also demonstrate this behavior and point to that code, so we
> will know what you are alluding to.

Here is the line of code:
https://git.savannah.gnu.org/cgit/emacs.git/tree/lisp/emacs-lisp/lisp.el#n107.
When the region is active, and no prefix arg is given to mark-sexp, the
function resets `arg` as follows:

(setq arg (if arg (prefix-numeric-value arg)
              (if (< (mark) (point)) -1 1)))

When no prefix arg is given, when the region is active, it sets arg to
either 1 or -1, depending on the relative positions of point and mark.

The behavior can be seen in the instructions above, but here's a simpler
way to see it:

1. `emacs -Q --eval '(progn (insert "foo bar baz") (goto-char 5))`
2. C-space. (Set mark)
3. M-f. (forward word). We have now set up the situation I was referring to
-- point is set after mark, and mark is active.
4. C-M-@. Here, we see mark-sexp extend region backwards without ever using
C-x C-x (exchange-point-and-mark). The feature of extending the region
backwards cannot be provided by exchange-point-and-mark.

On Wed, Apr 26, 2023 at 2:28 AM Eli Zaretskii <eliz@gnu.org> wrote:

> > Cc: Ruijie Yu <ruijie@netyu.xyz>, Stefan Monnier <
> monnier@iro.umontreal.ca>,
> >  62892@debbugs.gnu.org
> > From: Zachary Kanfer <zkanfer@gmail.com>
> > Date: Wed, 26 Apr 2023 00:41:45 -0400
> >
> > The documentation for mark-sexp says:
> >
> > > Set mark ARG sexps from point.
> > > The place mark goes is the same place C-M-<right> would
> > > move to with the same argument.
> >
> > This is correct but misleading.
>
> Please elaborate: how could it mislead?
>
> > Worse still is the next part:
> >
> > > Interactively, if this command is repeated
> > > or (in Transient Mark mode) if the mark is active,
> > > it marks the next ARG sexps after the ones already marked.
> >
> > This says it marks sexps *after* the ones already marked. This is
> incorrect; if point is *after* mark, and
> > mark is active, this function marks sexps *before* the ones already
> marked.
>
> I cannot reproduce this behavior, if I understand your description
> correctly.  Please show a recipe, starting from "emacs -Q", to
> reproduce.
>
> > > In my opinion, the description of that feature should not be part of
> the
> > > mark-sexp command documentation, because the feature is actually
> > > provided by C-x C-x (exchange-point-and-mark).
> >
> > One way for this situation to occur is by using C-x C-x, yes, but it's
> not the only way. You can set point,
> > move forward sexps, and then calling mark-sexp will mark sexps backwards.
> >
> > There is specific code in mark-sexp to check which direction to move; it
> should be documented as
> > such.
>
> Please also demonstrate this behavior and point to that code, so we
> will know what you are alluding to.
>
> Thanks.
>

[-- Attachment #2: Type: text/html, Size: 6642 bytes --]

^ permalink raw reply	[flat|nested] 43+ messages in thread

* bug#62892: proposal to extend mark-sexp to go forward and backward on command
  2023-04-27  2:37             ` Zachary Kanfer
@ 2023-04-27 12:25               ` Eli Zaretskii
  2023-04-27 18:12                 ` Juri Linkov
  0 siblings, 1 reply; 43+ messages in thread
From: Eli Zaretskii @ 2023-04-27 12:25 UTC (permalink / raw)
  To: Zachary Kanfer, Juri Linkov; +Cc: ruijie, monnier, 62892, mardani29

> From: Zachary Kanfer <zkanfer@gmail.com>
> Date: Wed, 26 Apr 2023 22:37:58 -0400
> Cc: mardani29@yahoo.es, ruijie@netyu.xyz, monnier@iro.umontreal.ca, 
> 	62892@debbugs.gnu.org
> 
> > > Worse still is the next part:
> > >
> > > > Interactively, if this command is repeated
> > > > or (in Transient Mark mode) if the mark is active,
> > > > it marks the next ARG sexps after the ones already marked.
> > >
> > > This says it marks sexps *after* the ones already marked. This is incorrect; if point is *after* mark,
> and
> > > mark is active, this function marks sexps *before* the ones already marked.
> >
> > I cannot reproduce this behavior, if I understand your description
> > correctly.  Please show a recipe, starting from "emacs -Q", to
> > reproduce.
> 
> Open Emacs with:
> 
> emacs -Q --eval '(progn (insert "foo bar baz") (goto-char 8) (set-mark 5))'
> 
> It will insert "foo bar baz", put point after "bar", and mark before "bar". Region contains "bar".
> 
> Then when we run mark-sexp, we expect to mark some sexps "after the ones already marked". That's
> what the docstring says.
> 
> After running the command above to open emacs, press C-M-@ to run mark-sexp. We should see
> sexps marked "after the ones already marked"; that is, we should see "bar baz" marked. But we don't.
> Instead, we see that "foo bar" is highlighted. That is, we have marked sexps *before* the ones already
> marked.
> 
> > > The documentation for mark-sexp says:
> > >
> > > > Set mark ARG sexps from point.
> > > > The place mark goes is the same place C-M-<right> would
> > > > move to with the same argument.
> > >
> > > This is correct but misleading.
> >
> > Please elaborate: how could it mislead?
> 
> "The same argument" is the misleading part. If I call mark-sexp with no argument, sometimes that code
> passes -1 to forward-sexp. So while I think I'm effectively passing a "1" to mark-sexp, instead -1 is
> passed to forward-sexp. This is somewhat explained by the next part of the docstring, but not entirely.
> Read with the rest of the docstring, it reinforces the belief that the command only marks sexps *after*
> point.

Thanks.

Yes, we have a small mess on our hands here.  Over the years, as
features were added to this command, the doc string became more and
more inaccurate.  Moreover, the behavior itself is somewhat
inconsistent: AFAIK this is the only command that accepts a numeric
argument and yet behaves differently when invoked without an argument
vs with "C-u 1".

I tried to describe the behavior in the doc string as follows:

  (defun mark-sexp (&optional arg allow-extend)
    "Set mark ARG sexps from point or move mark one sexp.
  When called from Lisp with ALLOW-EXTEND ommitted or nil, mark is
  set ARG sexps from point; ARG defaults to 1.
  With ALLOW-EXTEND non-nil (interactively, with prefix argument),
  the place mark goes is the same place \\[forward-sexp] would move
  with the same value of ARG; if the mark is active, it moves ARG
  sexps from its current position, otherwise it is set ARG sexps
  from point; ARG defaults to 1.
  When invoked interactively without a prefix argument and no active
  region, mark moves one sexp forward.
  When invoked interactively without a prefix argument, and region
  is active, mark moves one sexp away of point (i.e., forward
  if mark is at or after point, back if mark is before point), thus
  extending the region by one sexp.  Since the direction of region
  extension depends on the relative position of mark and point, you
  can change the direction by \\[exchange-point-and-mark].
  This command assumes point is not in a string or comment."

It is still somewhat complicated and confusing, but at least it's
accurate, I think.





^ permalink raw reply	[flat|nested] 43+ messages in thread

* bug#62892: proposal to extend mark-sexp to go forward and backward on command
  2023-04-27 12:25               ` Eli Zaretskii
@ 2023-04-27 18:12                 ` Juri Linkov
  2023-04-28  5:28                   ` Zachary Kanfer
  2023-05-06  8:49                   ` Eli Zaretskii
  0 siblings, 2 replies; 43+ messages in thread
From: Juri Linkov @ 2023-04-27 18:12 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: ruijie, 62892, Zachary Kanfer, monnier, mardani29

> I tried to describe the behavior in the doc string as follows:
>
>   (defun mark-sexp (&optional arg allow-extend)
>     "Set mark ARG sexps from point or move mark one sexp.
>   When called from Lisp with ALLOW-EXTEND ommitted or nil, mark is
>   set ARG sexps from point; ARG defaults to 1.
>   With ALLOW-EXTEND non-nil (interactively, with prefix argument),
>   the place mark goes is the same place \\[forward-sexp] would move
>   with the same value of ARG; if the mark is active, it moves ARG
>   sexps from its current position, otherwise it is set ARG sexps
>   from point; ARG defaults to 1.
>   When invoked interactively without a prefix argument and no active
>   region, mark moves one sexp forward.
>   When invoked interactively without a prefix argument, and region
>   is active, mark moves one sexp away of point (i.e., forward
>   if mark is at or after point, back if mark is before point), thus
>   extending the region by one sexp.  Since the direction of region
>   extension depends on the relative position of mark and point, you
>   can change the direction by \\[exchange-point-and-mark].
>   This command assumes point is not in a string or comment."
>
> It is still somewhat complicated and confusing, but at least it's
> accurate, I think.

mark-sexp has a counterpart mark-word that has almost the same
implementation and docstring.  So this could be fixed in both places.





^ permalink raw reply	[flat|nested] 43+ messages in thread

* bug#62892: proposal to extend mark-sexp to go forward and backward on command
  2023-04-27 18:12                 ` Juri Linkov
@ 2023-04-28  5:28                   ` Zachary Kanfer
  2023-05-06  8:49                   ` Eli Zaretskii
  1 sibling, 0 replies; 43+ messages in thread
From: Zachary Kanfer @ 2023-04-28  5:28 UTC (permalink / raw)
  To: Juri Linkov; +Cc: ruijie, Eli Zaretskii, monnier, 62892, mardani29

[-- Attachment #1: Type: text/plain, Size: 4986 bytes --]

I made some minor changes below. Alongside my suggestions are explanations
as to why. This is a hard command to describe!

> (defun mark-sexp (&optional arg allow-extend)
>  "Set mark ARG sexps from point or move mark ARG sexps.

Mark can be moved ARG steps. Press C-M-@ C-M-@ C-u 3 C-M-@. There will be
five total sexps marked. I'm hoping this explains that case as well, and
giving an intuition for what this command does ("move mark ARG steps").

> When invoked interactively without a prefix argument and no active
> region, mark moves one sexp forward.

I moved this first, both because I suspect it's the most common use case,
but also because it's the the simplest to understand.

> When invoked interactively without a prefix argument, and region
> is active, mark moves one sexp away from point (i.e., forward
> if mark is at or after point, back if mark is before point), thus
> extending the region by one sexp.
> With ALLOW-EXTEND non-nil (interactively, with prefix argument),
> the place mark goes is the same place \\[forward-sexp] would move
> with the same value of ARG; if the mark is active, it moves ARG
> sexps from its current position, otherwise it is set ARG sexps
> from point.

Moved this earlier to keep the entire interactive block together.

> When the region is active, the direction the region is extended
> depends on the relative position of mark and point. This means the
> direction can be changed by pressing \\[exchange-point-and-mark]
> before this command..

I moved this to a separate section to simplify the earlier parts, and to
call out that this is possible whenever the region is active.

> When called from Lisp with ALLOW-EXTEND omitted or nil, mark is
> set ARG (defaulting to 1) sexps from point.

Removed extra m from "omitted".

> This command assumes point is not in a string or comment."

Altogether, the docstring with my suggestions looks like:

> (defun mark-sexp (&optional arg allow-extend)
>  "Set mark ARG sexps from point or move mark ARG sexps.
> When invoked interactively without a prefix argument and no active
> region, mark moves one sexp forward.
> When invoked interactively without a prefix argument, and region
> is active, mark moves one sexp away from point (i.e., forward
> if mark is at or after point, back if mark is before point), thus
> extending the region by one sexp.
> With ALLOW-EXTEND non-nil (interactively, with prefix argument),
> the place mark goes is the same place \\[forward-sexp] would move
> with the same value of ARG; if the mark is active, it moves ARG
> sexps from its current position, otherwise it is set ARG sexps
> from point.
> When the region is active, the direction the region is extended
> depends on the relative position of mark and point. This means the
> direction can be changed by pressing \\[exchange-point-and-mark]
> before this command.
> When called from Lisp with ALLOW-EXTEND omitted or nil, mark is
> set ARG (defaulting to 1) sexps from point.
> This command assumes point is not in a string or comment."

This is a complicated command, for sure -- which is partially why I want
simple functions to mark sexps forward and backward: to not have to think
about different cases. Can we fork off a discussion about those functions?
Having simple functions allows the user to do what they want without having
to learn complex nuance.

On Thu, Apr 27, 2023 at 2:14 PM Juri Linkov <juri@linkov.net> wrote:

> > I tried to describe the behavior in the doc string as follows:
> >
> >   (defun mark-sexp (&optional arg allow-extend)
> >     "Set mark ARG sexps from point or move mark one sexp.
> >   When called from Lisp with ALLOW-EXTEND ommitted or nil, mark is
> >   set ARG sexps from point; ARG defaults to 1.
> >   With ALLOW-EXTEND non-nil (interactively, with prefix argument),
> >   the place mark goes is the same place \\[forward-sexp] would move
> >   with the same value of ARG; if the mark is active, it moves ARG
> >   sexps from its current position, otherwise it is set ARG sexps
> >   from point; ARG defaults to 1.
> >   When invoked interactively without a prefix argument and no active
> >   region, mark moves one sexp forward.
> >   When invoked interactively without a prefix argument, and region
> >   is active, mark moves one sexp away of point (i.e., forward
> >   if mark is at or after point, back if mark is before point), thus
> >   extending the region by one sexp.  Since the direction of region
> >   extension depends on the relative position of mark and point, you
> >   can change the direction by \\[exchange-point-and-mark].
> >   This command assumes point is not in a string or comment."
> >
> > It is still somewhat complicated and confusing, but at least it's
> > accurate, I think.
>
> mark-sexp has a counterpart mark-word that has almost the same
> implementation and docstring.  So this could be fixed in both places.
>

[-- Attachment #2: Type: text/html, Size: 5728 bytes --]

^ permalink raw reply	[flat|nested] 43+ messages in thread

* bug#62892: proposal to extend mark-sexp to go forward and backward on command
  2023-04-23  5:33     ` Zachary Kanfer
  2023-04-25 22:26       ` Daniel Martín via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2023-04-28 17:04       ` Juri Linkov
  2023-04-28 19:28         ` Drew Adams
  2023-05-03  6:10         ` Zachary Kanfer
  1 sibling, 2 replies; 43+ messages in thread
From: Juri Linkov @ 2023-04-28 17:04 UTC (permalink / raw)
  To: Zachary Kanfer; +Cc: Ruijie Yu, Stefan Monnier, 62892

> Attached is a patch with a few updates:

Thanks for the patch.  It would be nice to have such commands
even not bound to default keys, so the users are free to bind
them to any keys.

> I'm not exactly sure of the best place to put the helper function, nor
> exactly how the different lisp files in Emacs work together. There's no
> provide statement; are all the files in lisp/emacs-lisp loaded at the same
> time? If so, I'll make the other relevant functions (for marking word,
> defun, page, paragraph, line, and char).

Let's see:
- mark-sexp and mark-defun are defined in emacs-lisp/lisp.el
- mark-page in textmodes/page.el
- mark-paragraph in textmodes/paragraphs.el
- mark-word in simple.el

So looks like the best place to define the helper is simple.el,
before mark-word.

> +(defun mark--helper (move-fn number-of-things)

A nicer name would be 'mark-thing' as a reference to thingatpt.el.

> +  "Use MOVE-FN to move NUMBER-OF-THINGS things, extending region over them.
> +
> +The MOVE-FN should take a numeric argument, and move that many
> +items forward (negative means backward).
> +
> +NUMBER-OF-THINGS is the number of additional things to move."

Another variant is to use a single argument JUMPFORM like
in 'isearch-yank-internal' that allows not to leak the
prefix argument to the helper function:

  (defun isearch-yank-char (&optional arg)
    (isearch-yank-internal (lambda () (forward-char arg) (point))))





^ permalink raw reply	[flat|nested] 43+ messages in thread

* bug#62892: proposal to extend mark-sexp to go forward and backward on command
  2023-04-28 17:04       ` Juri Linkov
@ 2023-04-28 19:28         ` Drew Adams
  2023-05-04  4:48           ` Zachary Kanfer
  2023-05-03  6:10         ` Zachary Kanfer
  1 sibling, 1 reply; 43+ messages in thread
From: Drew Adams @ 2023-04-28 19:28 UTC (permalink / raw)
  To: Juri Linkov, Zachary Kanfer
  Cc: Ruijie Yu, Stefan Monnier, 62892@debbugs.gnu.org

> > +(defun mark--helper (move-fn number-of-things)
> 
> A nicer name would be 'mark-thing' as a reference to thingatpt.el.

FWIW, I have a different take on this.

Is it an "internal" function?  Then its name should
maybe use `--'.  (But why should it be internal?)

Is it a helper function?  Then its name should maybe
use a suffix that indicates that, such as `-helper'
or `-1' (old-school Lisp, I suppose).

`mark-thing' should be reserved for a function that
takes a THING name as arg: `sexp', `page', etc.,
instead of a movement function such as `forward-sexp'.
___

FWIW, I think MOVE-FN is a fine name for the argument.
My own preference, and what I use in my code, is the
name FORWARD-THING-FUNCTION.
___

FWIW, in my library isearch+.el), I use the arg name
THING for a thing name, not a movement or other
function.

E.g.: Function `isearchp-in-thing-p' is a helper
function for defining specific THING-type predicates,
such as `isearch(-not)-in-email-address-p'.
___

FWIW, my library `thing-cmds.el' has a command named
`mark-things', which prompts for a THING type as arg:

 mark-things is an alias for 'select-things' in 'thing-cmds.el'.

 (mark-things THING &optional ARG ALLOW-EXTEND)

 Set point at one end of THING and set mark ARG THINGs from point.
 THING is a symbol that names a type of thing.  Interactively, you are
 prompted for it.  Completion is available (lax).

 (If THING doesn't have an associated `forward-'THING operation then
 do nothing.)

 Put mark at the same place command `forward-'THING would move point
 with the same prefix argument.

 Put point at the beginning of THING, unless the prefix argument (ARG)
 is negative, in which case put it at the end of THING.

 If `select-things' is repeated or if the mark is active (in Transient
 Mark mode), then it marks the next ARG THINGs, after the ones already
 marked.  In this case the type of THING used is whatever was used the
 last time `select-things' was called - you are not prompted for it.

 This region extension reusing the last type of THING happens even if
 the active region is empty.  This means that you can, for instance,
 just use `C-SPC' to activate an empty region and then use
 `select-things' to select more THINGS of the last kind selected.

 If there is no THING at point, and `thgcmd-use-nearest-thing-flag' is
 non-nil, then select a THING near point.






^ permalink raw reply	[flat|nested] 43+ messages in thread

* bug#62892: proposal to extend mark-sexp to go forward and backward on command
  2023-04-28 17:04       ` Juri Linkov
  2023-04-28 19:28         ` Drew Adams
@ 2023-05-03  6:10         ` Zachary Kanfer
  2023-05-03 17:29           ` Juri Linkov
  1 sibling, 1 reply; 43+ messages in thread
From: Zachary Kanfer @ 2023-05-03  6:10 UTC (permalink / raw)
  To: Juri Linkov; +Cc: Ruijie Yu, Stefan Monnier, 62892

[-- Attachment #1: Type: text/plain, Size: 4537 bytes --]

> Thanks for the patch.  It would be nice to have such commands
> even not bound to default keys, so the users are free to bind
> them to any keys.

That's my hope, unless sufficiently good default keys can be found. I like
C-M-space and C-M-S-space, which are both currently bound to mark-sexp, but
changing the default keys is not trivially done.

> So looks like the best place to define the helper is simple.el,
> before mark-word.

Sure! I'll get a patch out for this.

> Another variant is to use a single argument JUMPFORM like
> in 'isearch-yank-internal' that allows not to leak the
> prefix argument to the helper function:

This is tempting. The downside I'm seeing to this -- which I'll think more
about to see if I can get around it -- is that we don't know if we need to
call JUMPFORM from point or mark.

We can do it from both, something like:

(defun mark--helper (fn-to-find-new-mark)
  "Extend region by calling FN-TO-FIND-NEW-MARK.

The MOVE-FN should take a numeric argument, and move that many
items forward (negative means backward).

NUMBER-OF-THINGS is the number of additional things to move."
  (if (use-region-p)
      (let* ((beginning-of-region (region-beginning))
             (end-of-region (region-end))
             (at-end-of-region (= end-of-region (point)))
             (move-from-front (save-excursion (goto-char
beginning-of-region)
                                              (funcall fn-to-find-new-mark)
                                              (point)))
             (move-from-end (save-excursion (goto-char end-of-region)
                                            (funcall fn-to-find-new-mark)
                                            (point)))
             (new-beginning-of-region (min beginning-of-region
move-from-front))
             (new-end-of-region (max end-of-region move-from-end)))
        (goto-char (if at-end-of-region
                       new-end-of-region
                     new-beginning-of-region))
        (set-mark (if at-end-of-region
                      new-beginning-of-region
                    new-end-of-region)))
    (progn (push-mark (save-excursion
                        (funcall fn-to-find-new-mark)
                        (point)))
           (activate-mark))))

Downsides include:

1. We have to call the function twice each time. This doesn't seem like
such a big deal unless it's expensive or has side effects -- neither of
which should be the case.
2. The current implementation errors when there are no more objects to
mark. This doesn't. I think we probably could error if we don't change the
region.
3. I'm not 100% convinced this will always do the right thing. I would like
to be.
4. I'm not sure going to one argument is worth it. The two arguments seem
pretty simple; changing to one argument might add more complexity than it
removes.

On Fri, Apr 28, 2023 at 1:07 PM Juri Linkov <juri@linkov.net> wrote:

> > Attached is a patch with a few updates:
>
> Thanks for the patch.  It would be nice to have such commands
> even not bound to default keys, so the users are free to bind
> them to any keys.
>
> > I'm not exactly sure of the best place to put the helper function, nor
> > exactly how the different lisp files in Emacs work together. There's no
> > provide statement; are all the files in lisp/emacs-lisp loaded at the
> same
> > time? If so, I'll make the other relevant functions (for marking word,
> > defun, page, paragraph, line, and char).
>
> Let's see:
> - mark-sexp and mark-defun are defined in emacs-lisp/lisp.el
> - mark-page in textmodes/page.el
> - mark-paragraph in textmodes/paragraphs.el
> - mark-word in simple.el
>
> So looks like the best place to define the helper is simple.el,
> before mark-word.
>
> > +(defun mark--helper (move-fn number-of-things)
>
> A nicer name would be 'mark-thing' as a reference to thingatpt.el.
>
> > +  "Use MOVE-FN to move NUMBER-OF-THINGS things, extending region over
> them.
> > +
> > +The MOVE-FN should take a numeric argument, and move that many
> > +items forward (negative means backward).
> > +
> > +NUMBER-OF-THINGS is the number of additional things to move."
>
> Another variant is to use a single argument JUMPFORM like
> in 'isearch-yank-internal' that allows not to leak the
> prefix argument to the helper function:
>
>   (defun isearch-yank-char (&optional arg)
>     (isearch-yank-internal (lambda () (forward-char arg) (point))))
>

[-- Attachment #2: Type: text/html, Size: 5802 bytes --]

^ permalink raw reply	[flat|nested] 43+ messages in thread

* bug#62892: proposal to extend mark-sexp to go forward and backward on command
  2023-05-03  6:10         ` Zachary Kanfer
@ 2023-05-03 17:29           ` Juri Linkov
  0 siblings, 0 replies; 43+ messages in thread
From: Juri Linkov @ 2023-05-03 17:29 UTC (permalink / raw)
  To: Zachary Kanfer; +Cc: Ruijie Yu, Stefan Monnier, 62892

>> Thanks for the patch.  It would be nice to have such commands
>> even not bound to default keys, so the users are free to bind
>> them to any keys.
>
> That's my hope, unless sufficiently good default keys can be found. I like
> C-M-space and C-M-S-space, which are both currently bound to mark-sexp, but
> changing the default keys is not trivially done.

Please also note that the reason why the current single binding is sufficient
is because it's needed only to extend the region at the opposite side of
the selected region where the mark is located, i.e. it only moves the mark.
Whereas to move the region boundary under point is easy with sexp navigation
commands (that keep the region active).  However, your two commands
are duplicating the task of moving point.  But maybe this is easier to use
for some users.

>> Another variant is to use a single argument JUMPFORM like
>> in 'isearch-yank-internal' that allows not to leak the
>> prefix argument to the helper function:
>
> This is tempting. The downside I'm seeing to this -- which I'll think more
> about to see if I can get around it -- is that we don't know if we need to
> call JUMPFORM from point or mark.

Indeed, because you need to handle motion in two directions.





^ permalink raw reply	[flat|nested] 43+ messages in thread

* bug#62892: proposal to extend mark-sexp to go forward and backward on command
  2023-04-28 19:28         ` Drew Adams
@ 2023-05-04  4:48           ` Zachary Kanfer
  2023-05-08 12:28             ` Zachary Kanfer
  0 siblings, 1 reply; 43+ messages in thread
From: Zachary Kanfer @ 2023-05-04  4:48 UTC (permalink / raw)
  To: Drew Adams; +Cc: Ruijie Yu, Stefan Monnier, 62892@debbugs.gnu.org, Juri Linkov

[-- Attachment #1: Type: text/plain, Size: 3600 bytes --]

> Is it an "internal" function?  Then its name should
> maybe use `--'.  (But why should it be internal?)

Hrm, I figured it would be an internal function because it's intended to be
wrapped by other code. But this describes a whole lot of functions. So it
can't be that.

I suppose that if there are other types of things that are created that one
might want to mark, then a user could use this method to mark them. So
perhaps it shouldn't be internal -- it really could be used by other code.

> Is it a helper function?  Then its name should maybe
> use a suffix that indicates that, such as `-helper'
> or `-1' (old-school Lisp, I suppose).

It's certainly a helper function -- it's intended to be called by a bunch
of different functions we write.

> `mark-thing' should be reserved for a function that
> takes a THING name as arg: `sexp', `page', etc.,
> instead of a movement function such as `forward-sexp'.

This makes a lot of sense to me.

On Fri, Apr 28, 2023 at 3:28 PM Drew Adams <drew.adams@oracle.com> wrote:

> > > +(defun mark--helper (move-fn number-of-things)
> >
> > A nicer name would be 'mark-thing' as a reference to thingatpt.el.
>
> FWIW, I have a different take on this.
>
> Is it an "internal" function?  Then its name should
> maybe use `--'.  (But why should it be internal?)
>
> Is it a helper function?  Then its name should maybe
> use a suffix that indicates that, such as `-helper'
> or `-1' (old-school Lisp, I suppose).
>
> `mark-thing' should be reserved for a function that
> takes a THING name as arg: `sexp', `page', etc.,
> instead of a movement function such as `forward-sexp'.
> ___
>
> FWIW, I think MOVE-FN is a fine name for the argument.
> My own preference, and what I use in my code, is the
> name FORWARD-THING-FUNCTION.
> ___
>
> FWIW, in my library isearch+.el), I use the arg name
> THING for a thing name, not a movement or other
> function.
>
> E.g.: Function `isearchp-in-thing-p' is a helper
> function for defining specific THING-type predicates,
> such as `isearch(-not)-in-email-address-p'.
> ___
>
> FWIW, my library `thing-cmds.el' has a command named
> `mark-things', which prompts for a THING type as arg:
>
>  mark-things is an alias for 'select-things' in 'thing-cmds.el'.
>
>  (mark-things THING &optional ARG ALLOW-EXTEND)
>
>  Set point at one end of THING and set mark ARG THINGs from point.
>  THING is a symbol that names a type of thing.  Interactively, you are
>  prompted for it.  Completion is available (lax).
>
>  (If THING doesn't have an associated `forward-'THING operation then
>  do nothing.)
>
>  Put mark at the same place command `forward-'THING would move point
>  with the same prefix argument.
>
>  Put point at the beginning of THING, unless the prefix argument (ARG)
>  is negative, in which case put it at the end of THING.
>
>  If `select-things' is repeated or if the mark is active (in Transient
>  Mark mode), then it marks the next ARG THINGs, after the ones already
>  marked.  In this case the type of THING used is whatever was used the
>  last time `select-things' was called - you are not prompted for it.
>
>  This region extension reusing the last type of THING happens even if
>  the active region is empty.  This means that you can, for instance,
>  just use `C-SPC' to activate an empty region and then use
>  `select-things' to select more THINGS of the last kind selected.
>
>  If there is no THING at point, and `thgcmd-use-nearest-thing-flag' is
>  non-nil, then select a THING near point.
>
>

[-- Attachment #2: Type: text/html, Size: 4530 bytes --]

^ permalink raw reply	[flat|nested] 43+ messages in thread

* bug#62892: proposal to extend mark-sexp to go forward and backward on command
  2023-04-27 18:12                 ` Juri Linkov
  2023-04-28  5:28                   ` Zachary Kanfer
@ 2023-05-06  8:49                   ` Eli Zaretskii
  1 sibling, 0 replies; 43+ messages in thread
From: Eli Zaretskii @ 2023-05-06  8:49 UTC (permalink / raw)
  To: Juri Linkov; +Cc: ruijie, 62892, zkanfer, monnier, mardani29

> From: Juri Linkov <juri@linkov.net>
> Cc: Zachary Kanfer <zkanfer@gmail.com>,  mardani29@yahoo.es,
>   ruijie@netyu.xyz,  monnier@iro.umontreal.ca,  62892@debbugs.gnu.org
> Date: Thu, 27 Apr 2023 21:12:55 +0300
> 
> > I tried to describe the behavior in the doc string as follows:
> >
> >   (defun mark-sexp (&optional arg allow-extend)
> >     "Set mark ARG sexps from point or move mark one sexp.
> >   When called from Lisp with ALLOW-EXTEND ommitted or nil, mark is
> >   set ARG sexps from point; ARG defaults to 1.
> >   With ALLOW-EXTEND non-nil (interactively, with prefix argument),
> >   the place mark goes is the same place \\[forward-sexp] would move
> >   with the same value of ARG; if the mark is active, it moves ARG
> >   sexps from its current position, otherwise it is set ARG sexps
> >   from point; ARG defaults to 1.
> >   When invoked interactively without a prefix argument and no active
> >   region, mark moves one sexp forward.
> >   When invoked interactively without a prefix argument, and region
> >   is active, mark moves one sexp away of point (i.e., forward
> >   if mark is at or after point, back if mark is before point), thus
> >   extending the region by one sexp.  Since the direction of region
> >   extension depends on the relative position of mark and point, you
> >   can change the direction by \\[exchange-point-and-mark].
> >   This command assumes point is not in a string or comment."
> >
> > It is still somewhat complicated and confusing, but at least it's
> > accurate, I think.
> 
> mark-sexp has a counterpart mark-word that has almost the same
> implementation and docstring.  So this could be fixed in both places.

Done on the emacs-29 branch.





^ permalink raw reply	[flat|nested] 43+ messages in thread

* bug#62892: proposal to extend mark-sexp to go forward and backward on command
  2023-05-04  4:48           ` Zachary Kanfer
@ 2023-05-08 12:28             ` Zachary Kanfer
  2023-05-18  3:17               ` Zachary Kanfer
  0 siblings, 1 reply; 43+ messages in thread
From: Zachary Kanfer @ 2023-05-08 12:28 UTC (permalink / raw)
  To: Drew Adams; +Cc: Ruijie Yu, Stefan Monnier, 62892@debbugs.gnu.org, Juri Linkov


[-- Attachment #1.1: Type: text/plain, Size: 4073 bytes --]

Attached is a patch with the following changes:

* Uses the helper function to create mark-foo-forward, mark-foo-backward
for word, paragraph, sexp, page, and defun.
* Adds tests for all of these.
* Adds these new functions to etc/NEWS and various .texi files in
doc/emacs/.

On Thu, May 4, 2023 at 12:48 AM Zachary Kanfer <zkanfer@gmail.com> wrote:

> > Is it an "internal" function?  Then its name should
> > maybe use `--'.  (But why should it be internal?)
>
> Hrm, I figured it would be an internal function because it's intended to
> be wrapped by other code. But this describes a whole lot of functions. So
> it can't be that.
>
> I suppose that if there are other types of things that are created that
> one might want to mark, then a user could use this method to mark them. So
> perhaps it shouldn't be internal -- it really could be used by other code.
>
> > Is it a helper function?  Then its name should maybe
> > use a suffix that indicates that, such as `-helper'
> > or `-1' (old-school Lisp, I suppose).
>
> It's certainly a helper function -- it's intended to be called by a bunch
> of different functions we write.
>
> > `mark-thing' should be reserved for a function that
> > takes a THING name as arg: `sexp', `page', etc.,
> > instead of a movement function such as `forward-sexp'.
>
> This makes a lot of sense to me.
>
> On Fri, Apr 28, 2023 at 3:28 PM Drew Adams <drew.adams@oracle.com> wrote:
>
>> > > +(defun mark--helper (move-fn number-of-things)
>> >
>> > A nicer name would be 'mark-thing' as a reference to thingatpt.el.
>>
>> FWIW, I have a different take on this.
>>
>> Is it an "internal" function?  Then its name should
>> maybe use `--'.  (But why should it be internal?)
>>
>> Is it a helper function?  Then its name should maybe
>> use a suffix that indicates that, such as `-helper'
>> or `-1' (old-school Lisp, I suppose).
>>
>> `mark-thing' should be reserved for a function that
>> takes a THING name as arg: `sexp', `page', etc.,
>> instead of a movement function such as `forward-sexp'.
>> ___
>>
>> FWIW, I think MOVE-FN is a fine name for the argument.
>> My own preference, and what I use in my code, is the
>> name FORWARD-THING-FUNCTION.
>> ___
>>
>> FWIW, in my library isearch+.el), I use the arg name
>> THING for a thing name, not a movement or other
>> function.
>>
>> E.g.: Function `isearchp-in-thing-p' is a helper
>> function for defining specific THING-type predicates,
>> such as `isearch(-not)-in-email-address-p'.
>> ___
>>
>> FWIW, my library `thing-cmds.el' has a command named
>> `mark-things', which prompts for a THING type as arg:
>>
>>  mark-things is an alias for 'select-things' in 'thing-cmds.el'.
>>
>>  (mark-things THING &optional ARG ALLOW-EXTEND)
>>
>>  Set point at one end of THING and set mark ARG THINGs from point.
>>  THING is a symbol that names a type of thing.  Interactively, you are
>>  prompted for it.  Completion is available (lax).
>>
>>  (If THING doesn't have an associated `forward-'THING operation then
>>  do nothing.)
>>
>>  Put mark at the same place command `forward-'THING would move point
>>  with the same prefix argument.
>>
>>  Put point at the beginning of THING, unless the prefix argument (ARG)
>>  is negative, in which case put it at the end of THING.
>>
>>  If `select-things' is repeated or if the mark is active (in Transient
>>  Mark mode), then it marks the next ARG THINGs, after the ones already
>>  marked.  In this case the type of THING used is whatever was used the
>>  last time `select-things' was called - you are not prompted for it.
>>
>>  This region extension reusing the last type of THING happens even if
>>  the active region is empty.  This means that you can, for instance,
>>  just use `C-SPC' to activate an empty region and then use
>>  `select-things' to select more THINGS of the last kind selected.
>>
>>  If there is no THING at point, and `thgcmd-use-nearest-thing-flag' is
>>  non-nil, then select a THING near point.
>>
>>

[-- Attachment #1.2: Type: text/html, Size: 5184 bytes --]

[-- Attachment #2: 0001-Add-foo-mark-forward-foo-mark-backward-for-various-f.patch --]
[-- Type: text/x-patch, Size: 26902 bytes --]

From 17386be5712159aa38f894c983fc48b21a234ae1 Mon Sep 17 00:00:00 2001
From: Zachary Kanfer <zkanfer@gmail.com>
Date: Sun, 16 Apr 2023 22:16:39 -0400
Subject: [PATCH] Add foo-mark-forward, foo-mark-backward, for various foo.

This adds methods to mark forward and backward for the given objects:

* word
* sexp
* defun
* paragraph
* page
---
 doc/emacs/mark.texi                     |  17 ++
 doc/emacs/programs.texi                 |   8 +
 doc/emacs/text.texi                     |  18 ++
 etc/NEWS                                |  20 ++
 lisp/emacs-lisp/lisp.el                 |  60 ++++++
 lisp/simple.el                          |  46 +++++
 lisp/textmodes/page.el                  |  14 ++
 lisp/textmodes/paragraphs.el            |  14 ++
 test/lisp/emacs-lisp/lisp-tests.el      | 262 ++++++++++++++++++++++++
 test/lisp/simple-tests.el               |  14 ++
 test/lisp/textmodes/page-tests.el       |  11 +
 test/lisp/textmodes/paragraphs-tests.el |  34 +++
 12 files changed, 518 insertions(+)

diff --git a/doc/emacs/mark.texi b/doc/emacs/mark.texi
index 3f1c76c1591..6aa12b78181 100644
--- a/doc/emacs/mark.texi
+++ b/doc/emacs/mark.texi
@@ -216,6 +216,15 @@ Marking Objects
 to advance the mark by @var{n} words.  A negative argument
 @minus{}@var{n} moves the mark back by @var{n} words.
 
+@findex mark-word-forward
+  @code{mark-word-forward} is similar to @code{mark-word}, but only
+  moves forward.
+
+@findex mark-word-backward
+  @code{mark-word-backward} is similar to @code{mark-word}, but only
+  moves backward.
+
+
 @kindex C-M-@@
 @findex mark-sexp
   Similarly, @kbd{C-M-@@} (@code{mark-sexp}) puts the mark at the end
@@ -224,6 +233,14 @@ Marking Objects
 positive or negative numeric arguments move the mark forward or
 backward by the specified number of expressions.
 
+@findex mark-sexp-forward
+  @code{mark-sexp-forward} is similar to @code{mark-sexp}, but only
+  moves forward.
+
+@findex mark-sexp-backward
+  @code{mark-sexp-backward} is similar to @code{mark-sexp}, but only
+  moves backward.
+
    The other commands in the above list set both point and mark, so as
 to delimit an object in the buffer.  @kbd{M-h} (@code{mark-paragraph})
 marks paragraphs (@pxref{Paragraphs}), @kbd{C-M-h} (@code{mark-defun})
diff --git a/doc/emacs/programs.texi b/doc/emacs/programs.texi
index 62df88a731e..4cd2007e225 100644
--- a/doc/emacs/programs.texi
+++ b/doc/emacs/programs.texi
@@ -230,6 +230,14 @@ Moving by Defuns
 negative argument moves back to an end of a defun, which is not quite
 the same as @kbd{C-M-a} with a positive argument.
 
+@findex mark-defun-forward
+  @code{mark-defun-forward} is similar to @code{mark-defun}, but only
+  moves forward.
+
+@findex mark-defun-backward
+  @code{mark-defun-backward} is similar to @code{mark-defun}, but only
+  moves backward.
+
 @kindex C-M-h @r{(C mode)}
 @findex c-mark-function
   To operate on the current defun, use @kbd{C-M-h}
diff --git a/doc/emacs/text.texi b/doc/emacs/text.texi
index 3d3f2562617..dcdcf18ad92 100644
--- a/doc/emacs/text.texi
+++ b/doc/emacs/text.texi
@@ -314,6 +314,15 @@ Paragraphs
   If you set a fill prefix, then paragraphs are delimited by all lines
 which don't start with the fill prefix.  @xref{Filling}.
 
+@findex mark-paragraph-forward
+  @code{mark-paragraph-forward} is similar to @code{mark-paragraph},
+  but only moves forward.
+
+@findex mark-paragraph-backward
+  @code{mark-paragraph-backward} is similar to @code{mark-paragraph},
+  but only moves backward.
+
+
 @vindex paragraph-start
 @vindex paragraph-separate
   The precise definition of a paragraph boundary is controlled by the
@@ -394,6 +403,15 @@ Pages
 relative to the current one.  Zero means the current page, one means
 the next page, and @minus{}1 means the previous one.
 
+@findex mark-page-forward
+  @code{mark-page-forward} is similar to @code{mark-page}, but only
+  moves forward.
+
+@findex mark-page-backward
+  @code{mark-page-backward} is similar to @code{mark-page}, but only
+  moves backward.
+
+
 @kindex C-x l
 @findex count-lines-page
   The @kbd{C-x l} command (@code{count-lines-page}) is good for deciding
diff --git a/etc/NEWS b/etc/NEWS
index c61a9ec3c5f..74b4f056095 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -81,6 +81,26 @@ mistaken compositions, this will now work as well.
 This works like 'kill-matching-buffers', but without asking for
 confirmation.
 
+---
+** New commands 'mark-sexp-forward', 'mark-sexp-backward'.
+These work like mark-sexp, but explicitly allow sexps to be marked forward and backward.
+
+---
+** New commands 'mark-word-forward', 'mark-word-backward'.
+These work like mark-word, but explicitly allow words to be marked forward and backward.
+
+---
+** New commands 'mark-defun-forward', 'mark-defun-backward'.
+These work like mark-defun, but explicitly allow defuns to be marked forward and backward.
+
+---
+** New commands 'mark-paragraph-forward', 'mark-paragraph-backward'.
+These work like mark-paragraph, but explicitly allow paragraphs to be marked forward and backward.
+
+---
+** New commands 'mark-page-forward', 'mark-page-backward'.
+These work like mark-page, but explicitly allow pages to be marked forward and backward.
+
 \f
 * Changes in Specialized Modes and Packages in Emacs 30.1
 
diff --git a/lisp/emacs-lisp/lisp.el b/lisp/emacs-lisp/lisp.el
index 417c218c6d7..39bfe5d3e06 100644
--- a/lisp/emacs-lisp/lisp.el
+++ b/lisp/emacs-lisp/lisp.el
@@ -129,6 +129,52 @@ mark-sexp
 	    (point))
 	  nil t))))
 
+(defun mark--helper (move-fn number-of-things)
+  "Use MOVE-FN to move NUMBER-OF-THINGS things, extending region over them.
+
+The MOVE-FN should take a numeric argument, and move that many
+items forward (negative means backward).
+
+NUMBER-OF-THINGS is the number of additional things to move."
+  (if (use-region-p)
+      (let* ((forward (>= number-of-things 0))
+             (beginning-of-region (region-beginning))
+             (end-of-region (region-end))
+             (at-end-of-region (= end-of-region (point)))
+             (new-border-point
+              (save-excursion
+                (goto-char (if forward (region-end) (region-beginning)))
+                (condition-case nil
+                    (funcall move-fn number-of-things)
+                  (scan-error (user-error "No more in this direction!")))
+                (point)))
+             (new-beginning-of-region (min beginning-of-region new-border-point))
+             (new-end-of-region (max end-of-region new-border-point)))
+        (goto-char (if at-end-of-region
+                       new-end-of-region
+                     new-beginning-of-region))
+        (set-mark (if at-end-of-region
+                      new-beginning-of-region
+                    new-end-of-region)))
+    (progn (push-mark (save-excursion
+                        (funcall move-fn number-of-things)
+                        (point)))
+           (activate-mark))))
+
+(defun mark-sexp-forward (&optional number-of-expressions)
+  "Mark NUMBER-OF-EXPRESSIONS s-expressions forward.
+
+ Repeated calls to this mark more s-expressions."
+  (interactive "p")
+  (mark--helper #'forward-sexp (or number-of-expressions 1)))
+
+(defun mark-sexp-backward (&optional number-of-expressions)
+  "Mark NUMBER-OF-EXPRESSIONS s-expressions backward.
+
+ Repeated calls to this mark more s-expressions."
+  (interactive "p")
+  (mark--helper #'forward-sexp (- (or number-of-expressions 1))))
+
 (defun forward-list (&optional arg interactive)
   "Move forward across one balanced group of parentheses.
 This command will also work on other parentheses-like expressions
@@ -604,6 +650,20 @@ end-of-defun
           (funcall end-of-defun-function)
 	  (funcall skip))))))
 
+(defun mark-defun-forward (&optional number-of-defuns)
+  "Mark NUMBER-OF-DEFUNS defuns forward.
+
+ Repeated calls to this mark more defuns."
+  (interactive "p")
+  (mark--helper #'end-of-defun (or number-of-defuns 1)))
+
+(defun mark-defun-backward (&optional number-of-defuns)
+  "Mark NUMBER-OF-DEFUNS defuns backward.
+
+ Repeated calls to this mark more defuns."
+  (interactive "p")
+  (mark--helper #'end-of-defun (- (or number-of-defuns 1))))
+
 (defun mark-defun (&optional arg interactive)
   "Put mark at end of this defun, point at beginning.
 The defun marked is the one that contains point or follows point.
diff --git a/lisp/simple.el b/lisp/simple.el
index b621e1603bd..46ff7559a2c 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -8701,6 +8701,52 @@ backward-word
   (interactive "^p")
   (forward-word (- (or arg 1))))
 
+(defun mark--helper (move-fn number-of-things)
+  "Use MOVE-FN to move NUMBER-OF-THINGS things, extending region over them.
+
+The MOVE-FN should take a numeric argument, and move that many
+items forward (negative means backward).
+
+NUMBER-OF-THINGS is the number of additional things to move."
+  (if (use-region-p)
+      (let* ((forward (>= number-of-things 0))
+             (beginning-of-region (region-beginning))
+             (end-of-region (region-end))
+             (at-end-of-region (= end-of-region (point)))
+             (new-border-point
+              (save-excursion
+                (goto-char (if forward (region-end) (region-beginning)))
+                (condition-case nil
+                    (funcall move-fn number-of-things)
+                  (scan-error (user-error "No more in this direction!")))
+                (point)))
+             (new-beginning-of-region (min beginning-of-region new-border-point))
+             (new-end-of-region (max end-of-region new-border-point)))
+        (goto-char (if at-end-of-region
+                       new-end-of-region
+                     new-beginning-of-region))
+        (set-mark (if at-end-of-region
+                      new-beginning-of-region
+                    new-end-of-region)))
+    (progn (push-mark (save-excursion
+                        (funcall move-fn number-of-things)
+                        (point)))
+           (activate-mark))))
+
+(defun mark-word-forward (&optional number-of-words)
+  "Mark NUMBER-OF-WORDS words forward.
+
+ Repeated calls to this mark more words."
+  (interactive "p")
+  (mark--helper #'forward-word (or number-of-words 1)))
+
+(defun mark-word-backward (&optional number-of-words)
+  "Mark NUMBER-OF-WORDS words backward.
+
+ Repeated calls to this mark more words."
+  (interactive "p")
+  (mark--helper #'forward-word (- (or number-of-words 1))))
+
 (defun mark-word (&optional arg allow-extend)
   "Set mark ARG words away from point.
 The place mark goes is the same place \\[forward-word] would
diff --git a/lisp/textmodes/page.el b/lisp/textmodes/page.el
index 86a2762b0ee..afebd8fdb25 100644
--- a/lisp/textmodes/page.el
+++ b/lisp/textmodes/page.el
@@ -71,6 +71,20 @@ backward-page
   (or count (setq count 1))
   (forward-page (- count)))
 
+(defun mark-page-forward (&optional number-of-pages)
+  "Mark NUMBER-OF-PAGES pages forward.
+
+ Repeated calls to this mark more pages."
+  (interactive "p")
+  (mark--helper #'forward-page (or number-of-pages 1)))
+
+(defun mark-page-backward (&optional number-of-pages)
+  "Mark NUMBER-OF-PAGES pages backward.
+
+ Repeated calls to this mark more pages."
+  (interactive "p")
+  (mark--helper #'forward-page (- (or number-of-pages 1))))
+
 (defun mark-page (&optional arg)
   "Put mark at end of page, point at beginning.
 A numeric arg specifies to move forward or backward by that many pages,
diff --git a/lisp/textmodes/paragraphs.el b/lisp/textmodes/paragraphs.el
index 6c33380b6bd..a278d485681 100644
--- a/lisp/textmodes/paragraphs.el
+++ b/lisp/textmodes/paragraphs.el
@@ -360,6 +360,20 @@ backward-paragraph
   (or arg (setq arg 1))
   (forward-paragraph (- arg)))
 
+(defun mark-paragraph-forward (&optional number-of-paragraphs)
+  "Mark NUMBER-OF-PARAGRAPHS paragraphs forward.
+
+ Repeated calls to this mark more paragraphs."
+  (interactive "p")
+  (mark--helper #'forward-paragraph (or number-of-paragraphs 1)))
+
+(defun mark-paragraph-backward (&optional number-of-paragraphs)
+  "Mark NUMBER-OF-PARAGRAPHS paragraphs backward.
+
+ Repeated calls to this mark more paragraphs."
+  (interactive "p")
+  (mark--helper #'forward-paragraph (- (or number-of-paragraphs 1))))
+
 (defun mark-paragraph (&optional arg allow-extend)
   "Put point at beginning of this paragraph, mark at end.
 The paragraph marked is the one that contains point or follows point.
diff --git a/test/lisp/emacs-lisp/lisp-tests.el b/test/lisp/emacs-lisp/lisp-tests.el
index 2e5e2a740b1..3e28f7232e5 100644
--- a/test/lisp/emacs-lisp/lisp-tests.el
+++ b/test/lisp/emacs-lisp/lisp-tests.el
@@ -116,6 +116,207 @@ lisp-backward-sexp-2-bobp-and-subsequent
     (should (null ;; (should-error ;; No, per #13994
      (forward-sexp -1)))))
 
+(ert-deftest mark-sexp-forward-one-forward-check-point ()
+  (should (equal 14
+                 (with-temp-buffer (insert "(1 2)
+(3 4 5)
+(6)
+(7 8)")
+                                      (goto-char (point-min))
+                                      (forward-line)
+                                      (end-of-line)
+                                      (mark-sexp-forward)
+                                      (point)))))
+
+(ert-deftest mark-sexp-forward-one-forward-pass-value-check-point ()
+  (should (equal 14
+                 (with-temp-buffer (insert "(1 2)
+(3 4 5)
+(6)
+(7 8)")
+                                      (goto-char (point-min))
+                                      (forward-line)
+                                      (end-of-line)
+                                      (mark-sexp-forward 1)
+                                      (point)))))
+
+(ert-deftest mark-sexp-forward-one-forward-check-region ()
+  (should (equal "(6)"
+                 (with-temp-buffer (insert "(1 2)
+(3 4 5)
+(6)
+(7 8)")
+                                   (goto-char (point-min))
+                                   (forward-line 2)
+                                   (mark-sexp-forward)
+                                   (buffer-substring-no-properties (region-beginning)
+                                                                   (region-end))))))
+
+(ert-deftest mark-sexp-forward-one-forward-pass-value-check-region ()
+  (should (equal "(6)"
+                 (with-temp-buffer (insert "(1 2)
+(3 4 5)
+(6)
+(7 8)")
+                                   (goto-char (point-min))
+                                   (forward-line 2)
+                                   (mark-sexp-forward 1)
+                                   (buffer-substring-no-properties (region-beginning)
+                                                                   (region-end))))))
+
+(ert-deftest mark-sexp-backward-one-backward-check-point ()
+  (should (equal 14
+                 (with-temp-buffer (insert "(1 2)
+(3 4 5)
+(6)
+(7 8)")
+                                   (goto-char (point-min))
+                                   (forward-line)
+                                   (end-of-line)
+                                   (mark-sexp-backward)
+                                   (point)))))
+
+(ert-deftest mark-sexp-backward-one-backward-check-region ()
+  (should (equal "(3 4 5)"
+                 (with-temp-buffer (insert "(1 2)
+(3 4 5)
+(6)
+(7 8)")
+                                   (goto-char (point-min))
+                                   (forward-line)
+                                   (end-of-line)
+                                   (mark-sexp-backward)
+                                   (buffer-substring-no-properties (region-beginning)
+                                                                   (region-end))))))
+
+(ert-deftest mark-sexp-one-forward-then-one-backward-check-point ()
+  (should (equal 7
+                 (with-temp-buffer (insert "(1 2)
+(3 4 5)
+(6)
+(7 8)")
+                                   (goto-char (point-min))
+                                   (forward-line)
+                                   (end-of-line)
+                                   (mark-sexp-forward)
+                                   (mark-sexp-backward)
+                                   (point)))))
+
+(ert-deftest mark-sexp-one-forward-then-one-backward-check-region ()
+  (should (equal "(3 4 5)
+(6)"
+                 (with-temp-buffer (insert "(1 2)
+(3 4 5)
+(6)
+(7 8)")
+                                   (goto-char (point-min))
+                                   (forward-line)
+                                   (end-of-line)
+                                   (mark-sexp-forward)
+                                   (mark-sexp-backward)
+                                   (buffer-substring-no-properties (region-beginning)
+                                                                   (region-end))))))
+
+(ert-deftest mark-sexp-one-forward-then-one-backward-then-one-forward-check-point ()
+  (should (equal 7
+                 (with-temp-buffer (insert "(1 2)
+(3 4 5)
+(6)
+(7 8)")
+                                   (goto-char (point-min))
+                                   (forward-line)
+                                   (end-of-line)
+                                   (mark-sexp-forward)
+                                   (mark-sexp-backward)
+                                   (mark-sexp-forward)
+                                   (point)))))
+
+(ert-deftest mark-sexp-one-forward-then-one-backward-then-one-forward-check-region ()
+  (should (equal 7
+                 (with-temp-buffer (insert "(1 2)
+(3 4 5)
+(6)
+(7 8)")
+                                   (goto-char (point-min))
+                                   (forward-line)
+                                   (end-of-line)
+                                   (mark-sexp-forward)
+                                   (mark-sexp-backward)
+                                   (mark-sexp-forward)
+                                   (point)))))
+
+
+
+(ert-deftest mark-sexp-forward-one-forward-one-back-one-forward-check-region ()
+  (should (equal "(3 4 5)
+(6)
+(7 8)"
+                 (with-temp-buffer (insert "(1 2)
+(3 4 5)
+(6)
+(7 8)")
+                                   (goto-char (point-min))
+                                   (forward-line)
+                                   (end-of-line)
+                                   (mark-sexp-forward)
+                                   (mark-sexp-backward)
+                                   (mark-sexp-forward)
+                                   (buffer-substring-no-properties (region-beginning)
+                                                                   (region-end))))))
+
+(ert-deftest mark-sexp-forward-two-forward-check-point ()
+  (should (equal 14
+                 (with-temp-buffer (insert "(1 2)
+(3 4 5)
+(6)
+(7 8)")
+                                   (goto-char (point-min))
+                                   (forward-line)
+                                   (end-of-line)
+                                   (mark-sexp-forward 2)
+                                   (point)))))
+
+(ert-deftest mark-sexp-forward-two-forward-check-region ()
+  (should (equal "
+(6)
+(7 8)"
+                 (with-temp-buffer (insert "(1 2)
+(3 4 5)
+(6)
+(7 8)")
+                                   (goto-char (point-min))
+                                   (forward-line)
+                                   (end-of-line)
+                                   (mark-sexp-forward 2)
+                                   (buffer-substring-no-properties (region-beginning)
+                                                                   (region-end))))))
+
+(ert-deftest mark-sexp-backward-two-backward-check-point ()
+  (should (equal 14
+                 (with-temp-buffer (insert "(1 2)
+(3 4 5)
+(6)
+(7 8)")
+                                   (goto-char (point-min))
+                                   (forward-line)
+                                   (end-of-line)
+                                   (mark-sexp-backward 2)
+                                   (point)))))
+
+(ert-deftest mark-sexp-backward-two-backward-check-region ()
+  (should (equal "(1 2)
+(3 4 5)"
+                 (with-temp-buffer (insert "(1 2)
+(3 4 5)
+(6)
+(7 8)")
+                                   (goto-char (point-min))
+                                   (forward-line)
+                                   (end-of-line)
+                                   (mark-sexp-backward 2)
+                                   (buffer-substring-no-properties (region-beginning)
+                                                                   (region-end))))))
+
 (ert-deftest lisp-delete-pair-parens ()
   "Test \\[delete-pair] with parens."
   (with-temp-buffer
@@ -369,6 +570,67 @@ elisp-tests-with-temp-buffer
 "
     "Test buffer for `mark-defun'."))
 
+(ert-deftest mark-defun-forward-one-forward-check-point ()
+  (should (equal 18
+                 (with-temp-buffer (insert "(defun foo () 2)
+
+(defun bar () 3)")
+                                      (goto-char (point-min))
+                                      (forward-line)
+                                      (mark-defun-forward)
+                                      (point)))))
+
+(ert-deftest mark-defun-forward-one-forward-check-region ()
+  (should (equal "
+(defun bar () 3)"
+                 (with-temp-buffer (insert "(defun foo () 2)
+
+(defun bar () 3)")
+                                      (goto-char (point-min))
+                                      (forward-line)
+                                      (mark-defun-forward)
+                                      (buffer-substring-no-properties (region-beginning)
+                                                                      (region-end))))))
+
+(ert-deftest mark-defun-backward-one-backward-check-point ()
+  (should (equal 18
+                 (with-temp-buffer (insert "(defun foo () 2)
+
+(defun bar () 3)")
+                                      (goto-char (point-min))
+                                      (forward-line)
+                                      (mark-defun-backward)
+                                      (point)))))
+
+(ert-deftest mark-defun-backward-one-backward-check-region ()
+  (should (equal "(defun foo () 2)
+"
+                 (with-temp-buffer (insert "(defun foo () 2)
+
+(defun bar () 2)")
+                                      (goto-char (point-min))
+                                      (forward-line)
+                                      (mark-defun-backward)
+                                      (buffer-substring-no-properties (region-beginning)
+                                                                      (region-end))))))
+
+
+(ert-deftest mark-defun-backward-two-backward-check-region ()
+  (should (equal "(defun foo () 2)
+(defun bar () 3)"
+                 (with-temp-buffer (insert "(defun foo () 2)
+(defun bar () 3)
+(defun baz () 5)
+(defun biff () 7)")
+                                      (goto-char (point-min))
+                                      (forward-line)
+                                      (end-of-line)
+                                      (mark-defun-backward)
+                                      (mark-defun-backward)
+                                      (buffer-substring-no-properties (region-beginning)
+                                                                      (region-end))))))
+
+
 ;;; end-of-defun
 
 (ert-deftest end-of-defun-twice ()
diff --git a/test/lisp/simple-tests.el b/test/lisp/simple-tests.el
index 28d8120f143..ba460d3cc01 100644
--- a/test/lisp/simple-tests.el
+++ b/test/lisp/simple-tests.el
@@ -115,6 +115,20 @@ simple-transpose-subr
   (should (equal (simple-test--transpositions (transpose-sexps -2))
                  '("(s1) (s4)" . " (s2) (s3) (s5)"))))
 
+\f
+;;; `mark-word-forward', `mark-word-backward'
+(ert-deftest mark-word-forward-two-backwards-check-region ()
+  (should (equal "defg hi j"
+                 (with-temp-buffer
+                   (insert "abc defg hi j klmno")
+                   (goto-char (point-min))
+                   (forward-char 11);;after "hi"
+                   (mark-word-forward)
+                   (mark-word-backward)
+                   (mark-word-backward)
+                   (buffer-substring-no-properties (region-beginning)
+                                                   (region-end))))))
+
 \f
 ;;; `newline'
 (ert-deftest newline ()
diff --git a/test/lisp/textmodes/page-tests.el b/test/lisp/textmodes/page-tests.el
index 4bfa8d9941c..0f142ee505b 100644
--- a/test/lisp/textmodes/page-tests.el
+++ b/test/lisp/textmodes/page-tests.el
@@ -57,6 +57,17 @@ page-tests-backward-page
     (backward-page -2)
     (should (= (point) (point-max)))))
 
+(ert-deftest mark-page-forward-twice-backward-oncecheck-region ()
+  (should (equal "\nbar\n\f\nbaz\n\f\nbiff\n\f"
+                 (with-temp-buffer (insert "foo\n\f\nbar\n\f\nbaz\n\f\nbiff\n\f\nbang")
+                                   (goto-char (point-min))
+                                   (forward-line 3)
+                                   (mark-page-forward)
+                                   (mark-page-forward)
+                                   (mark-page-backward)
+                                   (buffer-substring-no-properties (region-beginning)
+                                                                   (region-end))))))
+
 (defun page-tests--region-string ()
   "Return the contents of the region as a string."
   (buffer-substring (region-beginning) (region-end)))
diff --git a/test/lisp/textmodes/paragraphs-tests.el b/test/lisp/textmodes/paragraphs-tests.el
index 81e88113c2a..75a09811c7d 100644
--- a/test/lisp/textmodes/paragraphs-tests.el
+++ b/test/lisp/textmodes/paragraphs-tests.el
@@ -54,6 +54,40 @@ paragraphs-tests-mark-paragraph
     (should (equal (mark) 7))))
 ;;;  (should-error (mark-paragraph 0)))
 
+(ert-deftest paragraphs-tests-mark-paragraph-forward-two-backward-check-region ()
+  (should (equal "
+A second begins here, but is
+way way longer, but on multiple
+lines because the paragraph
+is filled..
+
+And a third paragraph. It's kind
+of short.
+
+Paragraph four! It's shorter.
+"
+                 (with-temp-buffer
+                   (insert "First paragraph here.
+
+A second begins here, but is
+way way longer, but on multiple
+lines because the paragraph
+is filled..
+
+And a third paragraph. It's kind
+of short.
+
+Paragraph four! It's shorter.
+
+The shortest yet.")
+                   (goto-char (point-min))
+                   (forward-line 9)
+                   (mark-paragraph-forward)
+                   (mark-paragraph-backward)
+                   (mark-paragraph-backward)
+                   (buffer-substring-no-properties (region-beginning)
+                                                   (region-end))))))
+
 (ert-deftest paragraphs-tests-kill-paragraph ()
   (with-temp-buffer
     (insert "AA\nAA\n\nBB\nBB\n")
-- 
2.38.4


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* bug#62892: proposal to extend mark-sexp to go forward and backward on command
  2023-05-08 12:28             ` Zachary Kanfer
@ 2023-05-18  3:17               ` Zachary Kanfer
  2023-05-18  6:52                 ` Eli Zaretskii
  2023-05-22 22:02                 ` Richard Stallman
  0 siblings, 2 replies; 43+ messages in thread
From: Zachary Kanfer @ 2023-05-18  3:17 UTC (permalink / raw)
  To: Drew Adams; +Cc: Ruijie Yu, Stefan Monnier, 62892@debbugs.gnu.org, Juri Linkov

[-- Attachment #1: Type: text/plain, Size: 4415 bytes --]

Is there anything I can do to make this patch easier to evaluate? As far as
I'm aware, I've addressed all comments that have been made in this thread.

On Mon, May 8, 2023 at 8:28 AM Zachary Kanfer <zkanfer@gmail.com> wrote:

> Attached is a patch with the following changes:
>
> * Uses the helper function to create mark-foo-forward, mark-foo-backward
> for word, paragraph, sexp, page, and defun.
> * Adds tests for all of these.
> * Adds these new functions to etc/NEWS and various .texi files in
> doc/emacs/.
>
> On Thu, May 4, 2023 at 12:48 AM Zachary Kanfer <zkanfer@gmail.com> wrote:
>
>> > Is it an "internal" function?  Then its name should
>> > maybe use `--'.  (But why should it be internal?)
>>
>> Hrm, I figured it would be an internal function because it's intended to
>> be wrapped by other code. But this describes a whole lot of functions. So
>> it can't be that.
>>
>> I suppose that if there are other types of things that are created that
>> one might want to mark, then a user could use this method to mark them. So
>> perhaps it shouldn't be internal -- it really could be used by other code.
>>
>> > Is it a helper function?  Then its name should maybe
>> > use a suffix that indicates that, such as `-helper'
>> > or `-1' (old-school Lisp, I suppose).
>>
>> It's certainly a helper function -- it's intended to be called by a bunch
>> of different functions we write.
>>
>> > `mark-thing' should be reserved for a function that
>> > takes a THING name as arg: `sexp', `page', etc.,
>> > instead of a movement function such as `forward-sexp'.
>>
>> This makes a lot of sense to me.
>>
>> On Fri, Apr 28, 2023 at 3:28 PM Drew Adams <drew.adams@oracle.com> wrote:
>>
>>> > > +(defun mark--helper (move-fn number-of-things)
>>> >
>>> > A nicer name would be 'mark-thing' as a reference to thingatpt.el.
>>>
>>> FWIW, I have a different take on this.
>>>
>>> Is it an "internal" function?  Then its name should
>>> maybe use `--'.  (But why should it be internal?)
>>>
>>> Is it a helper function?  Then its name should maybe
>>> use a suffix that indicates that, such as `-helper'
>>> or `-1' (old-school Lisp, I suppose).
>>>
>>> `mark-thing' should be reserved for a function that
>>> takes a THING name as arg: `sexp', `page', etc.,
>>> instead of a movement function such as `forward-sexp'.
>>> ___
>>>
>>> FWIW, I think MOVE-FN is a fine name for the argument.
>>> My own preference, and what I use in my code, is the
>>> name FORWARD-THING-FUNCTION.
>>> ___
>>>
>>> FWIW, in my library isearch+.el), I use the arg name
>>> THING for a thing name, not a movement or other
>>> function.
>>>
>>> E.g.: Function `isearchp-in-thing-p' is a helper
>>> function for defining specific THING-type predicates,
>>> such as `isearch(-not)-in-email-address-p'.
>>> ___
>>>
>>> FWIW, my library `thing-cmds.el' has a command named
>>> `mark-things', which prompts for a THING type as arg:
>>>
>>>  mark-things is an alias for 'select-things' in 'thing-cmds.el'.
>>>
>>>  (mark-things THING &optional ARG ALLOW-EXTEND)
>>>
>>>  Set point at one end of THING and set mark ARG THINGs from point.
>>>  THING is a symbol that names a type of thing.  Interactively, you are
>>>  prompted for it.  Completion is available (lax).
>>>
>>>  (If THING doesn't have an associated `forward-'THING operation then
>>>  do nothing.)
>>>
>>>  Put mark at the same place command `forward-'THING would move point
>>>  with the same prefix argument.
>>>
>>>  Put point at the beginning of THING, unless the prefix argument (ARG)
>>>  is negative, in which case put it at the end of THING.
>>>
>>>  If `select-things' is repeated or if the mark is active (in Transient
>>>  Mark mode), then it marks the next ARG THINGs, after the ones already
>>>  marked.  In this case the type of THING used is whatever was used the
>>>  last time `select-things' was called - you are not prompted for it.
>>>
>>>  This region extension reusing the last type of THING happens even if
>>>  the active region is empty.  This means that you can, for instance,
>>>  just use `C-SPC' to activate an empty region and then use
>>>  `select-things' to select more THINGS of the last kind selected.
>>>
>>>  If there is no THING at point, and `thgcmd-use-nearest-thing-flag' is
>>>  non-nil, then select a THING near point.
>>>
>>>

[-- Attachment #2: Type: text/html, Size: 5717 bytes --]

^ permalink raw reply	[flat|nested] 43+ messages in thread

* bug#62892: proposal to extend mark-sexp to go forward and backward on command
  2023-05-18  3:17               ` Zachary Kanfer
@ 2023-05-18  6:52                 ` Eli Zaretskii
  2023-05-21  5:46                   ` Zachary Kanfer
  2023-05-22 22:02                 ` Richard Stallman
  1 sibling, 1 reply; 43+ messages in thread
From: Eli Zaretskii @ 2023-05-18  6:52 UTC (permalink / raw)
  To: Zachary Kanfer; +Cc: ruijie, 62892, monnier, drew.adams, juri

> Cc: Ruijie Yu <ruijie@netyu.xyz>, Stefan Monnier <monnier@iro.umontreal.ca>,
>  "62892@debbugs.gnu.org" <62892@debbugs.gnu.org>, Juri Linkov <juri@linkov.net>
> From: Zachary Kanfer <zkanfer@gmail.com>
> Date: Wed, 17 May 2023 23:17:01 -0400
> 
> Is there anything I can do to make this patch easier to evaluate? As far as I'm aware, I've addressed
> all comments that have been made in this thread.

My POV is still as it was before: I'm not sure we should add these new
commands, since the existing commands already provide this
functionality, if you use "C-x C-x" to switch the direction.

I've seen nothing in the discussion which made me change my mind.  Did
I overlook some convincing arguments?





^ permalink raw reply	[flat|nested] 43+ messages in thread

* bug#62892: proposal to extend mark-sexp to go forward and backward on command
  2023-05-18  6:52                 ` Eli Zaretskii
@ 2023-05-21  5:46                   ` Zachary Kanfer
  2023-05-21  5:58                     ` Eli Zaretskii
  0 siblings, 1 reply; 43+ messages in thread
From: Zachary Kanfer @ 2023-05-21  5:46 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: ruijie, 62892, monnier, drew.adams, juri

[-- Attachment #1: Type: text/plain, Size: 1566 bytes --]

I think I've made as good an argument as I'm going to. It basically boils
down to:

* if the keys are bound, it's quicker to call mark-foo-forward and then
mark-foo-backward than to call mark-foo, then exchange-point-and-mark, then
mark-foo again.
* This behavior is simpler and more predictable: mark-foo-forward always
marks forward. mark-foo sometimes marks forward and sometimes backwards.
The complexity of the various mark-foo functions can be seen in how many
cases the docstring has. The behavior of the mark-foo-forward,
mark-foo-backward functions can be gathered from the name, without reading
the docstrings.

I understand we have different opinions, so if this isn't convincing, I'll
bow out here. Thanks.

On Thu, May 18, 2023 at 2:52 AM Eli Zaretskii <eliz@gnu.org> wrote:

> > Cc: Ruijie Yu <ruijie@netyu.xyz>, Stefan Monnier <
> monnier@iro.umontreal.ca>,
> >  "62892@debbugs.gnu.org" <62892@debbugs.gnu.org>, Juri Linkov <
> juri@linkov.net>
> > From: Zachary Kanfer <zkanfer@gmail.com>
> > Date: Wed, 17 May 2023 23:17:01 -0400
> >
> > Is there anything I can do to make this patch easier to evaluate? As far
> as I'm aware, I've addressed
> > all comments that have been made in this thread.
>
> My POV is still as it was before: I'm not sure we should add these new
> commands, since the existing commands already provide this
> functionality, if you use "C-x C-x" to switch the direction.
>
> I've seen nothing in the discussion which made me change my mind.  Did
> I overlook some convincing arguments?
>

[-- Attachment #2: Type: text/html, Size: 2369 bytes --]

^ permalink raw reply	[flat|nested] 43+ messages in thread

* bug#62892: proposal to extend mark-sexp to go forward and backward on command
  2023-05-21  5:46                   ` Zachary Kanfer
@ 2023-05-21  5:58                     ` Eli Zaretskii
  2023-05-21 14:31                       ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 43+ messages in thread
From: Eli Zaretskii @ 2023-05-21  5:58 UTC (permalink / raw)
  To: Zachary Kanfer, Stefan Monnier; +Cc: ruijie, 62892, drew.adams, juri

> From: Zachary Kanfer <zkanfer@gmail.com>
> Date: Sun, 21 May 2023 01:46:21 -0400
> Cc: drew.adams@oracle.com, ruijie@netyu.xyz, monnier@iro.umontreal.ca, 
> 	62892@debbugs.gnu.org, juri@linkov.net
> 
> I think I've made as good an argument as I'm going to. It basically boils down to:
> 
> * if the keys are bound, it's quicker to call mark-foo-forward and then mark-foo-backward than to call
> mark-foo, then exchange-point-and-mark, then mark-foo again.
> * This behavior is simpler and more predictable: mark-foo-forward always marks forward. mark-foo
> sometimes marks forward and sometimes backwards. The complexity of the various mark-foo
> functions can be seen in how many cases the docstring has. The behavior of the mark-foo-forward,
> mark-foo-backward functions can be gathered from the name, without reading the docstrings.
> 
> I understand we have different opinions, so if this isn't convincing, I'll bow out here. Thanks.

Stefan, WDYT about this?





^ permalink raw reply	[flat|nested] 43+ messages in thread

* bug#62892: proposal to extend mark-sexp to go forward and backward on command
  2023-05-21  5:58                     ` Eli Zaretskii
@ 2023-05-21 14:31                       ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-05-21 14:39                         ` Eli Zaretskii
  2023-05-21 14:56                         ` Eshel Yaron via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 2 replies; 43+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-05-21 14:31 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: ruijie, juri, Zachary Kanfer, 62892, drew.adams

> Stefan, WDYT about this?

There's a tension: on the one hand, there's a large number of
alternative UIs with many slightly different commands from the ones we
have, so we can't just add every single one of them to Emacs (instead,
we aim to provide convenient building blocks for them), but on the other
hand, we also want to make it easy for end users who don't want to
program to use slightly different UIs.

Maybe the new building block is useful enough (i.e. can be used in
existing code, thus reducing overall complexity)?  I haven't looked
closely enough to have a clear opinion, I'm afraid.


        Stefan






^ permalink raw reply	[flat|nested] 43+ messages in thread

* bug#62892: proposal to extend mark-sexp to go forward and backward on command
  2023-05-21 14:31                       ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2023-05-21 14:39                         ` Eli Zaretskii
  2023-05-21 14:54                           ` Eli Zaretskii
  2023-05-21 14:56                         ` Eshel Yaron via Bug reports for GNU Emacs, the Swiss army knife of text editors
  1 sibling, 1 reply; 43+ messages in thread
From: Eli Zaretskii @ 2023-05-21 14:39 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: ruijie, juri, zkanfer, 62892, drew.adams

> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: Zachary Kanfer <zkanfer@gmail.com>,  ruijie@netyu.xyz,
>   62892@debbugs.gnu.org,  drew.adams@oracle.com,  juri@linkov.net
> Date: Sun, 21 May 2023 10:31:41 -0400
> 
> Maybe the new building block is useful enough (i.e. can be used in
> existing code, thus reducing overall complexity)?

That'd be preferable, certainly.  Enlarging the set of the commands is
not my preference.





^ permalink raw reply	[flat|nested] 43+ messages in thread

* bug#62892: proposal to extend mark-sexp to go forward and backward on command
  2023-05-21 14:39                         ` Eli Zaretskii
@ 2023-05-21 14:54                           ` Eli Zaretskii
  0 siblings, 0 replies; 43+ messages in thread
From: Eli Zaretskii @ 2023-05-21 14:54 UTC (permalink / raw)
  To: zkanfer; +Cc: ruijie, drew.adams, monnier, 62892, juri

> Cc: ruijie@netyu.xyz, juri@linkov.net, zkanfer@gmail.com, 62892@debbugs.gnu.org,
>  drew.adams@oracle.com
> Date: Sun, 21 May 2023 17:39:44 +0300
> From: Eli Zaretskii <eliz@gnu.org>
> 
> > Maybe the new building block is useful enough (i.e. can be used in
> > existing code, thus reducing overall complexity)?
> 
> That'd be preferable, certainly.  Enlarging the set of the commands is
> not my preference.

Btw, these new commands keep the complicated, hard-to-remember MO of
mark-sexp: they do different things depending on whether
transient-mark-mode is on or off and whether the region is or isn't
active.  Why is this a Good Thing?





^ permalink raw reply	[flat|nested] 43+ messages in thread

* bug#62892: proposal to extend mark-sexp to go forward and backward on command
  2023-05-21 14:31                       ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-05-21 14:39                         ` Eli Zaretskii
@ 2023-05-21 14:56                         ` Eshel Yaron via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-05-21 15:11                           ` Eli Zaretskii
  1 sibling, 1 reply; 43+ messages in thread
From: Eshel Yaron via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-05-21 14:56 UTC (permalink / raw)
  To: 62892; +Cc: drew.adams, zkanfer, juri, ruijie, monnier, eliz


One data point that I think is worth taking into consideration:
Currently, `mark-sexp` and `mark-defun` are not consistent with each
other.  This can be seen in the following example:

--8<---------------cut here---------------start------------->8---
(foo)
(bar)
(baz)
--8<---------------cut here---------------end--------------->8---

With point before `(bar)`, doing `C-2 C-M-SPC C-- C-M-SPC` leaves only
`(bar)` selected.  OTOH, doing `C-2 C-M-h C-- C-M-h` leaves all three
expressions selected.

In contrast, the proposed `mark-sexp-forward` and `mark-defun-forward`
are consistent with each other (both behave like `mark-defun` in the
above example).

I'm not sure if that's the preferred behavior, but I do think that
consistently between the different marking commands is a good thing.


-- 
Best,

Eshel





^ permalink raw reply	[flat|nested] 43+ messages in thread

* bug#62892: proposal to extend mark-sexp to go forward and backward on command
  2023-05-21 14:56                         ` Eshel Yaron via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2023-05-21 15:11                           ` Eli Zaretskii
  2023-05-21 15:41                             ` Eshel Yaron via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 43+ messages in thread
From: Eli Zaretskii @ 2023-05-21 15:11 UTC (permalink / raw)
  To: Eshel Yaron; +Cc: zkanfer, juri, ruijie, 62892, drew.adams, monnier

> From: Eshel Yaron <me@eshelyaron.com>
> Cc: Eli Zaretskii <eliz@gnu.org>,  Stefan Monnier
>  <monnier@iro.umontreal.ca>,  ruijie@netyu.xyz,  juri@linkov.net,  Zachary
>  Kanfer <zkanfer@gmail.com>,  62892@debbugs.gnu.org,  drew.adams@oracle.com
> Date: Sun, 21 May 2023 17:56:54 +0300
> 
> I'm not sure if that's the preferred behavior, but I do think that
> consistently between the different marking commands is a good thing.

Why do you think there should be consistency here?  These are
different commands which target different use-cases.

Did you read the doc string of C-M-SPC?  It does something
extra-special when transient-mark-mode is enabled and the region is
active.





^ permalink raw reply	[flat|nested] 43+ messages in thread

* bug#62892: proposal to extend mark-sexp to go forward and backward on command
  2023-05-21 15:11                           ` Eli Zaretskii
@ 2023-05-21 15:41                             ` Eshel Yaron via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 0 replies; 43+ messages in thread
From: Eshel Yaron via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-05-21 15:41 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: zkanfer, juri, ruijie, 62892, drew.adams, monnier

Eli Zaretskii <eliz@gnu.org> writes:

>> From: Eshel Yaron <me@eshelyaron.com>
>> 
>> I'm not sure if that's the preferred behavior, but I do think that
>> consistently between the different marking commands is a good thing.
>
> Why do you think there should be consistency here?  These are
> different commands which target different use-cases.
>

I see, so `mark-word` and `mark-sexp` differ from `mark-paragraph`,
`mark-defun` and `mark-page` by design.  That's apparent from the Info
manual on second look.  Thanks.





^ permalink raw reply	[flat|nested] 43+ messages in thread

* bug#62892: proposal to extend mark-sexp to go forward and backward on command
  2023-05-18  3:17               ` Zachary Kanfer
  2023-05-18  6:52                 ` Eli Zaretskii
@ 2023-05-22 22:02                 ` Richard Stallman
  2023-05-23 14:11                   ` Zachary Kanfer
  1 sibling, 1 reply; 43+ messages in thread
From: Richard Stallman @ 2023-05-22 22:02 UTC (permalink / raw)
  To: Zachary Kanfer; +Cc: ruijie, 62892, monnier, drew.adams, juri

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > > Attached is a patch with the following changes:
  > >
  > > * Uses the helper function to create mark-foo-forward, mark-foo-backward
  > > for word, paragraph, sexp, page, and defun.

I think these functions would make sense, but I wonder hwo they
would do users any good.

Are you envisioning that we would create standard key bindings
for these functions?

Are you envisioning that users would bind some of these functions
to keys themselves?

Are you envisioning that users would call these functions from their
own Lisp code?

Any of those would make sense in the abstract, but I doubt that any of
them would be convenient enough to make this change worth installing.



-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)







^ permalink raw reply	[flat|nested] 43+ messages in thread

* bug#62892: proposal to extend mark-sexp to go forward and backward on command
  2023-05-22 22:02                 ` Richard Stallman
@ 2023-05-23 14:11                   ` Zachary Kanfer
  2023-05-25 22:32                     ` Richard Stallman
  0 siblings, 1 reply; 43+ messages in thread
From: Zachary Kanfer @ 2023-05-23 14:11 UTC (permalink / raw)
  To: rms; +Cc: ruijie, 62892, monnier, drew.adams, juri

[-- Attachment #1: Type: text/plain, Size: 2008 bytes --]

> Are you envisioning that we would create standard key bindings
> for these functions?

I was not suggesting that here. However,I think this would be ideal,
especially given that mark-sexp is bound to three different keybindings
(C-M-@, C-M-SPC, C-M-S-SPC). What is the process for finding out if a new
keybinding would be appropriate? Or for determining whether enough people
use a keybinding to keep it, vs changing it?

> Are you envisioning that users would bind some of these functions
> to keys themselves?

Yes. This is the main use-case I envisioned.

> Are you envisioning that users would call these functions from their
> own Lisp code?

This was not my main proposal, but users can do so if they want.

On Mon, May 22, 2023 at 6:02 PM Richard Stallman <rms@gnu.org> wrote:

> [[[ To any NSA and FBI agents reading my email: please consider    ]]]
> [[[ whether defending the US Constitution against all enemies,     ]]]
> [[[ foreign or domestic, requires you to follow Snowden's example. ]]]
>
>   > > Attached is a patch with the following changes:
>   > >
>   > > * Uses the helper function to create mark-foo-forward,
> mark-foo-backward
>   > > for word, paragraph, sexp, page, and defun.
>
> I think these functions would make sense, but I wonder hwo they
> would do users any good.
>
> Are you envisioning that we would create standard key bindings
> for these functions?
>
> Are you envisioning that users would bind some of these functions
> to keys themselves?
>
> Are you envisioning that users would call these functions from their
> own Lisp code?
>
> Any of those would make sense in the abstract, but I doubt that any of
> them would be convenient enough to make this change worth installing.
>
>
>
> --
> Dr Richard Stallman (https://stallman.org)
> Chief GNUisance of the GNU Project (https://gnu.org)
> Founder, Free Software Foundation (https://fsf.org)
> Internet Hall-of-Famer (https://internethalloffame.org)
>
>
>

[-- Attachment #2: Type: text/html, Size: 2814 bytes --]

^ permalink raw reply	[flat|nested] 43+ messages in thread

* bug#62892: proposal to extend mark-sexp to go forward and backward on command
  2023-05-23 14:11                   ` Zachary Kanfer
@ 2023-05-25 22:32                     ` Richard Stallman
  2023-05-26  6:06                       ` Eli Zaretskii
  0 siblings, 1 reply; 43+ messages in thread
From: Richard Stallman @ 2023-05-25 22:32 UTC (permalink / raw)
  To: Zachary Kanfer; +Cc: ruijie, 62892, monnier, drew.adams, juri

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

I don't think we could find standard key bindings that are easy enough
to be worth thinking about.

  > > Are you envisioning that users would bind some of these functions
  > > to keys themselves?

  > Yes. This is the main use-case I envisioned.

This is not outright unreasonable.  I still doubt they would
interest many users, and I would not favor documenting these
features fully in the Emacs Manual.

-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)







^ permalink raw reply	[flat|nested] 43+ messages in thread

* bug#62892: proposal to extend mark-sexp to go forward and backward on command
  2023-05-25 22:32                     ` Richard Stallman
@ 2023-05-26  6:06                       ` Eli Zaretskii
  2023-05-31  3:23                         ` Zachary Kanfer
  0 siblings, 1 reply; 43+ messages in thread
From: Eli Zaretskii @ 2023-05-26  6:06 UTC (permalink / raw)
  To: zkanfer, rms; +Cc: ruijie, juri, monnier, 62892, drew.adams

> Cc: ruijie@netyu.xyz, 62892@debbugs.gnu.org, monnier@iro.umontreal.ca,
>  drew.adams@oracle.com, juri@linkov.net
> From: Richard Stallman <rms@gnu.org>
> Date: Thu, 25 May 2023 18:32:56 -0400
> 
> I don't think we could find standard key bindings that are easy enough
> to be worth thinking about.
> 
>   > > Are you envisioning that users would bind some of these functions
>   > > to keys themselves?
> 
>   > Yes. This is the main use-case I envisioned.
> 
> This is not outright unreasonable.  I still doubt they would
> interest many users, and I would not favor documenting these
> features fully in the Emacs Manual.

After some more thinking, I came to the conclusion that I can only
support adding these new commands if they would work in a much more
predictable fashion: always move forward/back by ARG sexps and set the
region on all the sexps they moved across.  IOW, no change in behavior
depending on whether transient-mark-mode is ON or OFF, no change in
behavior depending on whether the region is active or not, and no
confusing notion of "extending the region" lumped into them.

Adding such simple commands could cater to those users who want
predictable marking behavior; perhaps those user will also want to
rebind C-M-f and C-M-b to these new commands.

But adding new commands that still change behavior in mysterious ways
depending on transient-mark-mode and active region is not something I
would like to do.

Sorry for bringing this up so late, I probably should have said this
at the very beginning of this discussion, if I were thinking fast
enough to realize this back then.





^ permalink raw reply	[flat|nested] 43+ messages in thread

* bug#62892: proposal to extend mark-sexp to go forward and backward on command
  2023-05-26  6:06                       ` Eli Zaretskii
@ 2023-05-31  3:23                         ` Zachary Kanfer
  2023-05-31 12:01                           ` Eli Zaretskii
  0 siblings, 1 reply; 43+ messages in thread
From: Zachary Kanfer @ 2023-05-31  3:23 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: rms, juri, ruijie, 62892, drew.adams, monnier

[-- Attachment #1: Type: text/plain, Size: 3085 bytes --]

This is interesting. Let me see if I'm understanding properly. In this,
I'll talk only about sexps, but I believe this argument should apply to all
the forms we've talked about (word, sexp, paragraph, defun, page). These
commands should:

1. Always move forward/back by ARG sexps (defaulting to 1), setting the
region on all sexps it moves across.

I'm in agreement with #1, for sure. That is the basis for what I wanted
initially.

2. Ignore whether transient-mark-mode is enabled.
3. Don't change behavior if the region is active or not.

#2 and #3 I believe can be considered together. There are a few things that
could do this, but I think what you're saying is that this function should
*only* move mark. That is, point should stay the same no matter what is
called here. Additionally, it should activate mark. Is that what you meant?

> But adding new commands that still change behavior in mysterious ways
> depending on transient-mark-mode and active region is not something I
> would like to do.

My understanding was that #'use-region-p (which checks transient-mark-mode,
and whether the region is active) is a standard way for determining whether
to act on the region or not, and should generally be looked at before
acting on the region. Is that not accurate?


On Fri, May 26, 2023 at 2:06 AM Eli Zaretskii <eliz@gnu.org> wrote:

> > Cc: ruijie@netyu.xyz, 62892@debbugs.gnu.org, monnier@iro.umontreal.ca,
> >  drew.adams@oracle.com, juri@linkov.net
> > From: Richard Stallman <rms@gnu.org>
> > Date: Thu, 25 May 2023 18:32:56 -0400
> >
> > I don't think we could find standard key bindings that are easy enough
> > to be worth thinking about.
> >
> >   > > Are you envisioning that users would bind some of these functions
> >   > > to keys themselves?
> >
> >   > Yes. This is the main use-case I envisioned.
> >
> > This is not outright unreasonable.  I still doubt they would
> > interest many users, and I would not favor documenting these
> > features fully in the Emacs Manual.
>
> After some more thinking, I came to the conclusion that I can only
> support adding these new commands if they would work in a much more
> predictable fashion: always move forward/back by ARG sexps and set the
> region on all the sexps they moved across.  IOW, no change in behavior
> depending on whether transient-mark-mode is ON or OFF, no change in
> behavior depending on whether the region is active or not, and no
> confusing notion of "extending the region" lumped into them.
>
> Adding such simple commands could cater to those users who want
> predictable marking behavior; perhaps those user will also want to
> rebind C-M-f and C-M-b to these new commands.
>
> But adding new commands that still change behavior in mysterious ways
> depending on transient-mark-mode and active region is not something I
> would like to do.
>
> Sorry for bringing this up so late, I probably should have said this
> at the very beginning of this discussion, if I were thinking fast
> enough to realize this back then.
>

[-- Attachment #2: Type: text/html, Size: 4088 bytes --]

^ permalink raw reply	[flat|nested] 43+ messages in thread

* bug#62892: proposal to extend mark-sexp to go forward and backward on command
  2023-05-31  3:23                         ` Zachary Kanfer
@ 2023-05-31 12:01                           ` Eli Zaretskii
  2023-06-01  3:54                             ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 43+ messages in thread
From: Eli Zaretskii @ 2023-05-31 12:01 UTC (permalink / raw)
  To: Zachary Kanfer; +Cc: rms, juri, ruijie, 62892, drew.adams, monnier

> From: Zachary Kanfer <zkanfer@gmail.com>
> Date: Tue, 30 May 2023 23:23:13 -0400
> Cc: rms@gnu.org, ruijie@netyu.xyz, 62892@debbugs.gnu.org, 
> 	monnier@iro.umontreal.ca, drew.adams@oracle.com, juri@linkov.net
> 
> This is interesting. Let me see if I'm understanding properly. In this, I'll talk only about sexps, but I
> believe this argument should apply to all the forms we've talked about (word, sexp, paragraph, defun,
> page). These commands should:
> 
> 1. Always move forward/back by ARG sexps (defaulting to 1), setting the region on all sexps it moves
> across.
> 
> I'm in agreement with #1, for sure. That is the basis for what I wanted initially.
> 
> 2. Ignore whether transient-mark-mode is enabled.
> 3. Don't change behavior if the region is active or not.
> 
> #2 and #3 I believe can be considered together. There are a few things that could do this, but I think
> what you're saying is that this function should *only* move mark.That is, point should stay the same no
> matter what is called here. Additionally, it should activate mark. Is that what you meant?

No, it should only move point, not the mark.  The mark should stay
where point was before invoking the command.

Whether it should activate the mark is open to discussion.  One
possibility is that the command will work like shift-select commands.
Another possibility is that it should activate the mark only if
transient-mark-mode is turned ON, like other commands that push the
mark.

> My understanding was that #'use-region-p (which checks transient-mark-mode, and whether the region
> is active) is a standard way for determining whether to act on the region or not, and should generally
> be looked at before acting on the region. Is that not accurate?

This is correct, but only for commands that do something with the text
in the region: limit search/replace to it, or spell-check the text in
it, etc.  mark-sexp doesn't do anything like that, it actually
_modifies_ the region.  So the fact that it changes its effect
depending on whether the region is active is IMO pretty confusing and
unexpected.





^ permalink raw reply	[flat|nested] 43+ messages in thread

* bug#62892: proposal to extend mark-sexp to go forward and backward on command
  2023-05-31 12:01                           ` Eli Zaretskii
@ 2023-06-01  3:54                             ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-06-01  6:32                               ` Eli Zaretskii
  0 siblings, 1 reply; 43+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-06-01  3:54 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: rms, Zachary Kanfer, juri, ruijie, 62892, drew.adams

>> #2 and #3 I believe can be considered together. There are a few things
>> that could do this, but I think
>> what you're saying is that this function should *only* move mark.That is,
>> point should stay the same no
>> matter what is called here. Additionally, it should activate mark. Is that what you meant?
>
> No, it should only move point, not the mark.  The mark should stay
> where point was before invoking the command.

Hmm?  Really?
That would make it equivalent to `forward-sexp`, no?

> This is correct, but only for commands that do something with the text
> in the region: limit search/replace to it, or spell-check the text in
> it, etc.  mark-sexp doesn't do anything like that, it actually
> _modifies_ the region.  So the fact that it changes its effect
> depending on whether the region is active is IMO pretty confusing and
> unexpected.

Agreed, tho for `mark-sexp` when `transient-mark-mode` is enabled, it
makes sense to treat "region not active" differently from "region
active", since `mark-sexp` mostly moves the mark but when the region is
not active, it means the mark is "an old obsolete mark" that the user
may not remember any more.


        Stefan






^ permalink raw reply	[flat|nested] 43+ messages in thread

* bug#62892: proposal to extend mark-sexp to go forward and backward on command
  2023-06-01  3:54                             ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2023-06-01  6:32                               ` Eli Zaretskii
  0 siblings, 0 replies; 43+ messages in thread
From: Eli Zaretskii @ 2023-06-01  6:32 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: rms, zkanfer, juri, ruijie, 62892, drew.adams

> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: Zachary Kanfer <zkanfer@gmail.com>,  rms@gnu.org,  ruijie@netyu.xyz,
>   62892@debbugs.gnu.org,  drew.adams@oracle.com,  juri@linkov.net
> Date: Wed, 31 May 2023 23:54:48 -0400
> 
> > No, it should only move point, not the mark.  The mark should stay
> > where point was before invoking the command.
> 
> Hmm?  Really?
> That would make it equivalent to `forward-sexp`, no?

That's exactly the idea: move like forward-sexp and mark the sexps
moved across.

> > This is correct, but only for commands that do something with the text
> > in the region: limit search/replace to it, or spell-check the text in
> > it, etc.  mark-sexp doesn't do anything like that, it actually
> > _modifies_ the region.  So the fact that it changes its effect
> > depending on whether the region is active is IMO pretty confusing and
> > unexpected.
> 
> Agreed, tho for `mark-sexp` when `transient-mark-mode` is enabled, it
> makes sense to treat "region not active" differently from "region
> active", since `mark-sexp` mostly moves the mark but when the region is
> not active, it means the mark is "an old obsolete mark" that the user
> may not remember any more.

I'm not lobbying for changing the behavior of mark-sexp.  It's too
late for that, no matter what my opinion about that is.  I'm saying
that it could make sense to have much simpler commands whose effect is
always predictable in advance, even if you don't use them frequently,
and even if you sometimes have transient-mark-mode on and sometimes
off.





^ permalink raw reply	[flat|nested] 43+ messages in thread

end of thread, other threads:[~2023-06-01  6:32 UTC | newest]

Thread overview: 43+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-04-17  2:25 bug#62892: proposal to extend mark-sexp to go forward and backward on command Zachary Kanfer
2023-04-17  3:06 ` Ruijie Yu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-04-20  5:25   ` Zachary Kanfer
2023-04-20  7:16     ` Eli Zaretskii
2023-04-21  5:04       ` Zachary Kanfer
2023-04-21  6:07         ` Eli Zaretskii
2023-04-21  7:24           ` Eshel Yaron via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-04-21  9:51           ` Visuwesh
2023-04-21 13:10   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-04-23  5:33     ` Zachary Kanfer
2023-04-25 22:26       ` Daniel Martín via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-04-26  4:41         ` Zachary Kanfer
2023-04-26  6:28           ` Eli Zaretskii
2023-04-27  2:37             ` Zachary Kanfer
2023-04-27 12:25               ` Eli Zaretskii
2023-04-27 18:12                 ` Juri Linkov
2023-04-28  5:28                   ` Zachary Kanfer
2023-05-06  8:49                   ` Eli Zaretskii
2023-04-28 17:04       ` Juri Linkov
2023-04-28 19:28         ` Drew Adams
2023-05-04  4:48           ` Zachary Kanfer
2023-05-08 12:28             ` Zachary Kanfer
2023-05-18  3:17               ` Zachary Kanfer
2023-05-18  6:52                 ` Eli Zaretskii
2023-05-21  5:46                   ` Zachary Kanfer
2023-05-21  5:58                     ` Eli Zaretskii
2023-05-21 14:31                       ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-05-21 14:39                         ` Eli Zaretskii
2023-05-21 14:54                           ` Eli Zaretskii
2023-05-21 14:56                         ` Eshel Yaron via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-05-21 15:11                           ` Eli Zaretskii
2023-05-21 15:41                             ` Eshel Yaron via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-05-22 22:02                 ` Richard Stallman
2023-05-23 14:11                   ` Zachary Kanfer
2023-05-25 22:32                     ` Richard Stallman
2023-05-26  6:06                       ` Eli Zaretskii
2023-05-31  3:23                         ` Zachary Kanfer
2023-05-31 12:01                           ` Eli Zaretskii
2023-06-01  3:54                             ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-06-01  6:32                               ` Eli Zaretskii
2023-05-03  6:10         ` Zachary Kanfer
2023-05-03 17:29           ` Juri Linkov
2023-04-17  7:11 ` Juri Linkov

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).