Subject: bug#62892: proposal to extend mark-sexp to go forward and backward on command

From: Zachary Kanfer <[email-masked]>
Date: Fri, 28 Apr 2023 01:28:09 -0400

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 <[email-masked]> 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.
>