]> git.eshelyaron.com Git - emacs.git/commitdiff
Make it easier to use Emacs as a script interpreter
authorLars Ingebrigtsen <larsi@gnus.org>
Mon, 18 Apr 2022 10:58:54 +0000 (12:58 +0200)
committerLars Ingebrigtsen <larsi@gnus.org>
Mon, 18 Apr 2022 10:59:03 +0000 (12:59 +0200)
* doc/emacs/cmdargs.texi (Initial Options): Document -x.
* lisp/startup.el (command-line-1): Add new -scripteval.
(command-line--eval-script): New function.

* src/emacs.c (main): Transform -x to -scripteval.
(standard_args): Add -x (bug#20682).

doc/emacs/cmdargs.texi
etc/NEWS
lisp/startup.el
src/emacs.c

index de1d5e0b2c36b34d7a7a8a3bad0934002696aaf3..946afb6fc1482bb73d59f61bd9760780bd9352cd 100644 (file)
@@ -294,6 +294,22 @@ which will invoke Emacs with @samp{--script} and supply the name of
 the script file as @var{file}.  Emacs Lisp then treats the @samp{#!}
 on this first line as a comment delimiter.
 
+@item -x
+@opindex -x
+This option can only be used in executable script files, and should be
+invoked like this:
+
+@example
+#!/usr/bin/emacs -x
+@end example
+
+This is like @samp{--script}, but suppresses loading the init files
+(like @code{--quick}), and can't be used on a normal command line
+(since it doesn't specify the script to load).  In addition, when it
+reaches the end of the script, it exits Emacs and uses the value of
+the final form as the exit value from the script (if the final value
+is numerical).  Otherwise, it will always exit with a zero value.
+
 @item --no-build-details
 @opindex --no-build-details
 @cindex build details
index ec56839c064dac81c4eb4d0788dd0114390afda8..3e7788277d3033d76bbf08e3c5315039d5834805 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -100,6 +100,17 @@ Saving Emacs Sessions" node in the Emacs manual for more details.
 \f
 * Startup Changes in Emacs 29.1
 
++++
+** Emacs can now be used more easily in an executable script.
+If you start an executable script with
+
+    #!/usr/bin/emacs -x
+
+Emac will start without reading any init files (like with --quick),
+and then execute the rest of the script file as Emacs Lisp.  When it
+reaches the end of the script, Emacs will exit with an exit code from
+the value of the final form.
+
 +++
 ** Emacs now supports setting 'user-emacs-directory' via '--init-directory'.
 
index ab7b81a707ebbc3295249e7e16f0c1ab07eb7267..353b5c78f17938eec74f55f7dd1016925a2535b8 100644 (file)
@@ -2664,7 +2664,7 @@ nil default-directory" name)
 
                     ;; This is used to handle -script.  It's not clear
                     ;; we need to document it (it is totally internal).
-                    ((member argi '("-scriptload"))
+                    ((member argi '("-scriptload" "-scripteval"))
                      (let* ((file (command-line-normalize-file-name
                                    (or argval (pop command-line-args-left))))
                             ;; Take file from default dir.
@@ -2677,7 +2677,10 @@ nil default-directory" name)
                        ;; actually exist on some systems.
                        (when (file-exists-p truename)
                          (setq file-ex truename))
-                       (command-line--load-script file-ex)))
+                       (if (equal argi "-scripteval")
+                           ;; This will kill Emacs.
+                           (command-line--eval-script file-ex)
+                         (command-line--load-script file-ex))))
 
                     ((equal argi "-insert")
                      (setq inhibit-startup-screen t)
@@ -2879,6 +2882,22 @@ nil default-directory" name)
          (delete-line))
        (eval-buffer buffer nil file nil t)))))
 
+(defun command-line--eval-script (file)
+  (load-with-code-conversion
+   file file nil t
+   (lambda (buffer _)
+     (with-current-buffer buffer
+       (goto-char (point-min))
+       (when (looking-at "#!")
+         (forward-line))
+       (let (value form)
+         (while (ignore-error 'end-of-file
+                  (setq form (read (current-buffer))))
+           (setq value (eval form t)))
+         (kill-emacs (if (numberp value)
+                         value
+                       0)))))))
+
 (defun command-line-normalize-file-name (file)
   "Collapse multiple slashes to one, to handle non-Emacs file names."
   (save-match-data
index 2fb62cb69af258c2f1a6d4a5de13d3d17d787b22..3100852b2c0ca93989b990024aea5e7bf87c6b9c 100644 (file)
@@ -296,7 +296,10 @@ Initialization options:\n\
                               -q --no-site-file --no-site-lisp --no-splash\n\
                               --no-x-resources\n\
 --script FILE               run FILE as an Emacs Lisp script\n\
---terminal, -t DEVICE       use DEVICE for terminal I/O\n\
+-x                          to be used in #!/usr/bin/emacs -x\n\
+                              and has approximately the same meaning\n\
+                             as -Q --script\n\
+--terminal, -t DEVICE       use DEVICE for terminal I/O\n              \
 --user, -u USER             load ~USER/.emacs instead of your own\n\
 \n\
 ",
@@ -2063,6 +2066,16 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
           no_site_lisp = 1;
       }
 
+    if (argmatch (argv, argc, "-x", 0, 1, &junk, &skip_args))
+      {
+       noninteractive = 1;
+       no_site_lisp = 1;
+       /* This is picked up in startup.el.  */
+       argv[skip_args - 1] = (char *) "-scripteval";
+       skip_args -= 1;
+       sort_args (argc, argv);
+      }
+
     /* Don't actually discard this arg.  */
     skip_args = count_before;
   }
@@ -2504,6 +2517,7 @@ static const struct standard_args standard_args[] =
   /* (Note that to imply -nsl, -Q is partially handled here.)  */
   { "-Q", "--quick", 55, 0 },
   { "-quick", 0, 55, 0 },
+  { "-x", 0, 55, 0 },
   { "-q", "--no-init-file", 50, 0 },
   { "-no-init-file", 0, 50, 0 },
   { "-init-directory", "--init-directory", 30, 1 },