unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Suggestion: two new commands: beginning-of-list and end-of-list
@ 2024-09-09 18:32 arthur miller
  2024-09-09 19:11 ` Eli Zaretskii
  2024-09-10 12:05 ` Yuri Khan
  0 siblings, 2 replies; 13+ messages in thread
From: arthur miller @ 2024-09-09 18:32 UTC (permalink / raw)
  To: emacs-devel@gnu.org


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

In elisp-mode.el, there is a function, IMO somewhat unfortunately named
"elisp--beginning-of-sexp".  What this function does is to place cursor at the
beginning of the innermost list, which we can perhaps call more conveniently,
"current list".

The function does so always, and is relatively well written, minor the case when
the cursor is placed in a literal string or outside a symbolic expression, say
between two top-level forms. In those cases, it jumps into the first string
before the current string, which might be anywhere in the file prior to the
current string, or to the beginning of the file.

I took me a liberty to rename this function and update the doc to a more
appropriate wording, and turn it into a command. I have also patched the
above mentioned cases when it is invoked in a literal string or outside of
 an expression.

As another consideration, I have moved this function into lisp.el (in
lisp/emacs-lisp/) in the sources.  It does not look like it has nothing
particularly specific to EmacsLisp per se, seems like it should work on any
"parenthesis"-language. I have tested it successfully in both CommonLisp and
EmacsLisp files.

I found only one user of elisp--beginning-of-sexp in the entire Emacs, and that
is the function directly above: elisp--fnsym-in-current-sexp.

Emacs already has few functions for motion over lists and symbolic expressions,
but actually not the one that places the cursor at the beginning of a list. I
think people use "lispy" to move several sexps at a time or cook their own via
paredit to move to the end of a list or beginning of a list. At least what I
have seen in some SX posts when looking around after I made the patch. I don't
 even have one myself, I use either C-f/b to move by words or paredit-forward to
move one expression at a time.

IMO it is a pitty to leave "elisp--beginning-of-sexp" underused, when it can
 perhaps be more useful to someone, so I suggest this little "re-furntituring" as a
 small quality-of-life improvement for Lisp programmers.

Of course, if there is a beginning-of-list, there should be end-of-list too? I
have prototyped one hastly, which just inverts the condition (works), but the
 proper  way would be to refactor out the common code and do the argument
 handling similar as in forward-sexp, or something like that.

TBH I am not sure how generally useful this is (it is to me), but if it is an
acceptable change, I can refactor out the common code, and format the patch
according to Emacs style, with NEWS entry and perhaps some tests (I tested
interactively only).

As extra chatter: a symbolic expression is either atom (non consp such as
literals or symbols) or a list:

> 1. Atomic symbols are S-expressions.
> 2. If e1 and e2 are S-expressions, so is (e1 . e2).

From the "Recursive Functions of Symbolic Expressions" by J. McCarthy (the paper
freely available online).

Thus elisp--beginning-of-sexp, is really a misnomer considering what it
does. Also, Emacs already has a function that actually does move cursor to the
beginning of a sexp, (forward-sexp -1) does it, and it does it correctly.

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

[-- Attachment #2: 0001-beginning-end-of-list.patch --]
[-- Type: application/octet-stream, Size: 4065 bytes --]

From 920174b47f19a3604e4978a8232d0703d4c53b79 Mon Sep 17 00:00:00 2001
From: arthur <arthur.miller@live.com>
Date: Mon, 9 Sep 2024 20:17:47 +0200
Subject: [PATCH] beginning/end-of-list

---
 lisp/emacs-lisp/lisp.el      | 60 ++++++++++++++++++++++++++++++++++++
 lisp/progmodes/elisp-mode.el | 26 +---------------
 2 files changed, 61 insertions(+), 25 deletions(-)

diff --git a/lisp/emacs-lisp/lisp.el b/lisp/emacs-lisp/lisp.el
index e65eec508d9..89c4cdde494 100644
--- a/lisp/emacs-lisp/lisp.el
+++ b/lisp/emacs-lisp/lisp.el
@@ -296,6 +296,66 @@ up-list
               (signal (car err) (cdr err)))))))
       (setq arg (- arg inc)))))
 
+(defun beginning-of-list ()
+  "Move cursor to the beginning of current list.
+
+Return the number of nested expressions the point was over or after."
+  (interactive)
+  (let ((parse-sexp-ignore-comments t)
+	(num-skipped-sexps 0)
+        (syntax (syntax-ppss)))
+    (unless (= 0 (nth 0 syntax)) ;; not in a list
+      (when (nth 3 syntax) ;; in a string
+        (goto-char (nth 8 syntax)))
+      (condition-case _
+	  (progn
+	    ;; First account for the case the point is directly over a
+	    ;; beginning of a nested sexp.
+	    (condition-case _
+	        (let ((p (point)))
+		  (forward-sexp -1)
+		  (forward-sexp 1)
+		  (when (< (point) p)
+		    (setq num-skipped-sexps 1)))
+	      (error))
+	    (while
+	        (let ((p (point)))
+		  (forward-sexp -1)
+		  (when (< (point) p)
+		    (setq num-skipped-sexps (1+ num-skipped-sexps))))))
+        (error)))
+    num-skipped-sexps))
+
+(defun end-of-list ()
+  "Move cursor to the end of current list.
+
+Return the number of nested expressions the point was over or after."
+  (interactive)
+  (let ((parse-sexp-ignore-comments t)
+	(num-skipped-sexps 0)
+        (syntax (syntax-ppss)))
+    (unless (= 0 (nth 0 syntax)) ;; not in a list
+      (when (nth 3 syntax) ;; in a string
+        (goto-char (nth 8 syntax)))
+      (condition-case _
+	  (progn
+	    ;; First account for the case the point is directly over a
+	    ;; beginning of a nested sexp.
+	    (condition-case _
+	        (let ((p (point)))
+		  (forward-sexp 1)
+		  (forward-sexp -1)
+		  (when (> (point) p)
+		    (setq num-skipped-sexps 1)))
+	      (error))
+	    (while
+	        (let ((p (point)))
+		  (forward-sexp 1)
+		  (when (> (point) p)
+		    (setq num-skipped-sexps (1+ num-skipped-sexps))))))
+        (error)))
+    num-skipped-sexps))
+
 (defun kill-sexp (&optional arg interactive)
   "Kill the sexp (balanced expression) following point.
 With ARG, kill that many sexps after point.
diff --git a/lisp/progmodes/elisp-mode.el b/lisp/progmodes/elisp-mode.el
index 9bf6f9217c8..7345301d2e5 100644
--- a/lisp/progmodes/elisp-mode.el
+++ b/lisp/progmodes/elisp-mode.el
@@ -2042,36 +2042,12 @@ elisp--docstring-first-line
 (defun elisp--fnsym-in-current-sexp ()
   (save-excursion
     (unless (nth 8 (syntax-ppss))
-      (let ((argument-index (1- (elisp--beginning-of-sexp))))
+      (let ((argument-index (1- (beginning-of-list))))
         ;; If we are at the beginning of function name, this will be -1.
         (when (< argument-index 0)
           (setq argument-index 0))
         (list (elisp--current-symbol) argument-index)))))
 
-;; Move to the beginning of current sexp.  Return the number of nested
-;; sexp the point was over or after.
-(defun elisp--beginning-of-sexp ()
-  (let ((parse-sexp-ignore-comments t)
-	(num-skipped-sexps 0))
-    (condition-case _
-	(progn
-	  ;; First account for the case the point is directly over a
-	  ;; beginning of a nested sexp.
-	  (condition-case _
-	      (let ((p (point)))
-		(forward-sexp -1)
-		(forward-sexp 1)
-		(when (< (point) p)
-		  (setq num-skipped-sexps 1)))
-	    (error))
-	  (while
-	      (let ((p (point)))
-		(forward-sexp -1)
-		(when (< (point) p)
-		  (setq num-skipped-sexps (1+ num-skipped-sexps))))))
-      (error))
-    num-skipped-sexps))
-
 ;; returns nil unless current word is an interned symbol.
 (defun elisp--current-symbol ()
   (let ((c (char-after (point))))
-- 
2.46.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread
* Re: Suggestion: two new commands: beginning-of-list and end-of-list
@ 2024-09-13 13:30 arthur miller
  0 siblings, 0 replies; 13+ messages in thread
From: arthur miller @ 2024-09-13 13:30 UTC (permalink / raw)
  To: Emanuel Berg; +Cc: emacs-devel@gnu.org

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

>> Small conventience might matter to people.
>> With backward-up-list you have to press at least one more
>> time, or if you are in a doc string you have to invoke
>> it again.
> ( ... )
>Small or big, that's up to anyone to decide. We take it.
>
>Emacs including Emacs Lisp has had a huge problem and has it
>still, and that is to neglect simple, small things.
>
>  ( ... )
>
>Speed, ergonomics and convenience in _everything_.
>Youngers don't read manual (most of them), they expect
>everything to be great day 1. And why not? In a way I agree.
>and 2) senior citizens cannot or have no time, mental
>discipline to acquire vast new skills. And as for professional
>IT people - what they need is actually the same, speed,
>ergonomics, convenience, because they need to be productive
>(and also enjoy/being able to work with the software all day
>every day).
>
>  ( ... )
>
>Streamline everything, cut corners for real with technology -
>don't rely on mere humans to implement human-invented
>conventions,

Sorry for cutting up a bit, I think it was well-formulated by you.
You are on the point most of the time. I just shortened a bit to
underline the most important points you made (in my opinions).

At least looking from the online questions, I think you are correct
about people either just looking at completion options, and probably
not reading the manual. I think for many users even something as
simple as this would be an improvement in Emacs:

(defun beginning-of-list ()
  "Move cursor to the beginning of current list."
  (interactive)
  (call-interactively #'backward-up-list)
  (forward-char))

(defun end-of-list ()
  "Move cursor to the end of current list"
  (interactive)
  (call-interactively #'up-list)
  (backward-char))

The naming is more descriptive of what commands do, and they automate
something. Automation is good, computers should do the work for humans
not the other way around. I would though argue that the other definition
of beginning/end-of-list are more convenient since they properly jump
out of the literal strings .

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

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

end of thread, other threads:[~2024-09-13 13:30 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-09-09 18:32 Suggestion: two new commands: beginning-of-list and end-of-list arthur miller
2024-09-09 19:11 ` Eli Zaretskii
2024-09-09 19:41   ` Sv: " arthur miller
2024-09-09 19:41     ` arthur miller
2024-09-10 11:30     ` Eli Zaretskii
2024-09-10 15:10       ` Sv: " arthur miller
2024-09-10 15:48         ` Eli Zaretskii
2024-09-11  5:39           ` Sv: " arthur miller
2024-09-12  4:24             ` Emanuel Berg
2024-09-11  3:17     ` Sv: " Karthik Chikmagalur
2024-09-11  5:48       ` Sv: " arthur miller
2024-09-10 12:05 ` Yuri Khan
  -- strict thread matches above, loose matches on Subject: below --
2024-09-13 13:30 arthur miller

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).