unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#65273: 30.0.50; [PATCH] Add a built-in Eshell 'compile' command
@ 2023-08-13 19:59 Jim Porter
  2023-08-16 17:04 ` Jim Porter
  0 siblings, 1 reply; 2+ messages in thread
From: Jim Porter @ 2023-08-13 19:59 UTC (permalink / raw)
  To: 65273

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

There are already a few built-in Eshell commands that pop up a 
compilation buffer when used interactively ("make" and the various 
"grep" commands). This patch adds a new, generic "compile" built-in so 
that it's easy for users to take advantage of this behavior for other 
programs (e.g. running "cmake" or "configure").

In addition, I expanded the documentation for how to discard built-in 
commands so that a user who *doesn't* like the new "compile" built-in 
can explicitly call the regular Emacs Lisp function.

[-- Attachment #2: 0001-Add-compile-builtin-command-for-Eshell.patch --]
[-- Type: text/plain, Size: 9660 bytes --]

From b243af2cb41fd9aa48629daaf5170e91ec630b1b Mon Sep 17 00:00:00 2001
From: Jim Porter <jporterbugs@gmail.com>
Date: Sun, 13 Aug 2023 12:07:39 -0700
Subject: [PATCH 1/2] Add 'compile' builtin command for Eshell

* lisp/eshell/em-unix.el (eshell-compile, eshell/compile): New
functions.
(eshell/make, eshell-grep): Use 'eshell-compile'.
(eshell/glimpse): It's no longer necessary to let-bind 'null-device';
'eshell-grep' no longer calls 'grep' (the Lisp function), which needed
'null-device' to be nil for this case.

* test/lisp/eshell/em-unix-tests.el: New file.

* doc/misc/eshell.texi (Built-ins): Document the 'compile' builtin.

* etc/NEWS: Announce this change.
---
 doc/misc/eshell.texi              | 11 +++++
 etc/NEWS                          | 10 ++++
 lisp/eshell/em-unix.el            | 80 ++++++++++++++++++++-----------
 test/lisp/eshell/em-unix-tests.el | 68 ++++++++++++++++++++++++++
 4 files changed, 141 insertions(+), 28 deletions(-)
 create mode 100644 test/lisp/eshell/em-unix-tests.el

diff --git a/doc/misc/eshell.texi b/doc/misc/eshell.texi
index ca31cb2589d..211b13c995c 100644
--- a/doc/misc/eshell.texi
+++ b/doc/misc/eshell.texi
@@ -523,6 +523,17 @@ Built-ins
 command @command{clear}, this command deletes content in the Eshell
 buffer.
 
+@item compile
+@cmindex compile
+Run an external command, sending its output to a compilation buffer if
+the command would output to the screen and is not part of a pipeline
+or subcommand.  This is particularly useful when defining aliases, so
+that interactively, the output shows up in a compilation buffer, but
+you can still pipe the output elsewhere if desired.  For example, if
+you have a grep-like command on your system, you might define an alias
+for it like so: @samp{alias mygrep 'compile --mode=grep-mode -- mygrep
+$*'}.
+
 @item cp
 @cmindex cp
 Copy a file to a new location or copy multiple files to the same
diff --git a/etc/NEWS b/etc/NEWS
index 0388cca97aa..06bbaddf2a1 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -291,6 +291,16 @@ using this new option.  (Or set 'display-buffer-alist' directly.)
 
 ** Eshell
 
++++
+*** New builtin Eshell command 'compile'.
+
+This command runs another command, sending its output to a compilation
+buffer when the command would output interatively.  This can be useful
+when defining aliases so that they produce a compilation buffer when
+appropriate, but still allow piping the output elsewhere if desired.
+For more information, see the "(eshell) Built-ins" node in the Eshell
+manual.
+
 +++
 *** New splice operator for Eshell dollar expansions.
 Dollar expansions in Eshell now let you splice the elements of the
diff --git a/lisp/eshell/em-unix.el b/lisp/eshell/em-unix.el
index a8c86b925bc..509b2d31819 100644
--- a/lisp/eshell/em-unix.el
+++ b/lisp/eshell/em-unix.el
@@ -692,19 +692,56 @@ eshell/cat
 
 ;; special front-end functions for compilation-mode buffers
 
+(defun eshell-compile (command args &optional method mode)
+  "Run an external COMMAND with ARGS using a compilation buffer when possible.
+COMMAND should be a list of command-line arguments.  By default,
+if the command is outputting to the screen and is not part of a
+pipeline or subcommand, open an compilation buffer to hold the
+results; otherwise, write the output on stdout.
+
+If METHOD is `interactive', always open a compilation buffer.  If
+METHOD is `plain', always write to stdout.
+
+MODE, if specified, is the major mode to set in the compilation
+buffer (see `compilation-start')."
+  (if (and (not (eq method 'interactive))
+           (or (eq method 'plain)
+               eshell-in-pipeline-p
+               eshell-in-subcommand-p
+               (not (eshell-interactive-output-p))))
+      (throw 'eshell-replace-command
+              (eshell-parse-command (concat "*" command) args))
+    (compile
+     (mapconcat #'shell-quote-argument
+                (eshell-stringify-list (flatten-tree (cons command args)))
+                " ")
+     mode)))
+
+(defun eshell/compile (&rest args)
+  "Run an external COMMAND using a compilation buffer when possible.
+See `eshell-compile'."
+  (eshell-eval-using-options
+   "compile" args
+   '((?m "mode" t mode "the mode to set in the compilation buffer")
+     (?i "interactive" 'interactive method "always open a compilation buffer")
+     (?p "plain" 'plain method "always write to stdout")
+     :usage "[-p | -i] [-m MODE] COMMAND...
+Run COMMAND in a compilation buffer when outputting to the screen and
+not part of a pipeline or subcommand."
+     :parse-leading-options-only)
+   (when (stringp mode)
+     (setq mode (intern mode)))
+   (eshell-compile (car args) (cdr args) method mode)))
+
+(put 'eshell/compile 'eshell-no-numeric-conversions t)
+
 (defun eshell/make (&rest args)
   "Use `compile' to do background makes.
 Fallback to standard make when called synchronously."
-  (if (and eshell-current-subjob-p
-	   (eshell-interactive-output-p))
-      (let ((compilation-process-setup-function
-	     (list 'lambda nil
-		   (list 'setq 'process-environment
-			 (list 'quote (eshell-copy-environment))))))
-	(compile (concat "make " (eshell-flatten-and-stringify args))))
-    (throw 'eshell-replace-command
-	   (eshell-parse-command "*make" (eshell-stringify-list
-					  (flatten-tree args))))))
+  (eshell-compile "make" args
+                  ;; Use plain output unless we're executing in the
+                  ;; background.
+                  (not eshell-current-subjob-p)))
 
 (put 'eshell/make 'eshell-no-numeric-conversions t)
 
@@ -777,22 +814,10 @@ eshell-grep
 external command."
   (if (and maybe-use-occur eshell-no-grep-available)
       (eshell-poor-mans-grep args)
-    (if (or eshell-plain-grep-behavior
-	    (not (and (eshell-interactive-output-p)
-		      (not eshell-in-pipeline-p)
-		      (not eshell-in-subcommand-p))))
-	(throw 'eshell-replace-command
-	       (eshell-parse-command (concat "*" command)
-				     (eshell-stringify-list
-				      (flatten-tree args))))
-      (let* ((args (mapconcat 'identity
-			      (mapcar 'shell-quote-argument
-				      (eshell-stringify-list
-				       (flatten-tree args)))
-			      " "))
-	     (cmd (format "%s -n %s" command args))
-	     compilation-scroll-output)
-	(grep cmd)))))
+    (eshell-compile command (cons "-n" args)
+                    (and eshell-plain-grep-behavior
+                         'interactive)
+                     #'grep-mode)))
 
 (defun eshell/grep (&rest args)
   "Use Emacs grep facility instead of calling external grep."
@@ -816,8 +841,7 @@ eshell/rgrep
 
 (defun eshell/glimpse (&rest args)
   "Use Emacs grep facility instead of calling external glimpse."
-  (let (null-device)
-    (eshell-grep "glimpse" (append '("-z" "-y") args))))
+  (eshell-grep "glimpse" (append '("-z" "-y") args)))
 
 ;; completions rules for some common UNIX commands
 
diff --git a/test/lisp/eshell/em-unix-tests.el b/test/lisp/eshell/em-unix-tests.el
new file mode 100644
index 00000000000..d7b6c55fe45
--- /dev/null
+++ b/test/lisp/eshell/em-unix-tests.el
@@ -0,0 +1,68 @@
+;;; em-unix-tests.el --- em-unix test suite  -*- lexical-binding:t -*-
+
+;; Copyright (C) 2023 Free Software Foundation, Inc.
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Tests for Eshell's implementation of various UNIX commands.
+
+;;; Code:
+
+(require 'ert)
+(require 'em-unix)
+
+(require 'eshell-tests-helpers
+         (expand-file-name "eshell-tests-helpers"
+                           (file-name-directory (or load-file-name
+                                                    default-directory))))
+
+;;; Tests:
+
+(ert-deftest em-unix-test/compile/interactive ()
+  "Check that `eshell/compile' opens a compilation buffer interactively."
+  (skip-unless (executable-find "echo"))
+  (with-temp-eshell
+   (eshell-match-command-output "compile echo hello"
+                                "#<buffer \\*compilation\\*>")
+   (with-current-buffer "*compilation*"
+     (forward-line 3)
+     (should (looking-at "echo hello")))))
+
+(ert-deftest em-unix-test/compile/noninteractive ()
+  "Check that `eshell/compile' writes to stdout noninteractively."
+  (skip-unless (executable-find "echo"))
+  (eshell-command-result-equal "compile echo hello"
+                               "hello\n"))
+
+(ert-deftest em-unix-test/compile/pipeline ()
+  "Check that `eshell/compile' writes to stdout from a pipeline."
+  (skip-unless (and (executable-find "echo")
+                    (executable-find "cat")))
+  (with-temp-eshell
+   (eshell-match-command-output "compile echo hello | *cat"
+                                "\\`hello\n")))
+
+(ert-deftest em-unix-test/compile/subcommand ()
+  "Check that `eshell/compile' writes to stdout from a subcommand."
+  (skip-unless (and (executable-find "echo")
+                    (executable-find "cat")))
+  (with-temp-eshell
+   (eshell-match-command-output "echo ${compile echo hello}"
+                                "\\`hello\n")))
+
+;; em-unix-tests.el ends here
-- 
2.25.1


[-- Attachment #3: 0002-Show-how-to-call-an-Elisp-function-of-the-same-name-.patch --]
[-- Type: text/plain, Size: 2271 bytes --]

From 055db4d875bbe84bb100f95170159bdd3d4e2891 Mon Sep 17 00:00:00 2001
From: Jim Porter <jporterbugs@gmail.com>
Date: Sun, 13 Aug 2023 12:33:17 -0700
Subject: [PATCH 2/2] Show how to call an Elisp function of the same name as an
 Eshell built-in

* doc/misc/eshell.texi (Built-ins): Expand documentation.
---
 doc/misc/eshell.texi | 31 +++++++++++++++++++++++--------
 1 file changed, 23 insertions(+), 8 deletions(-)

diff --git a/doc/misc/eshell.texi b/doc/misc/eshell.texi
index 211b13c995c..6890728a81d 100644
--- a/doc/misc/eshell.texi
+++ b/doc/misc/eshell.texi
@@ -409,8 +409,18 @@ Built-ins
 (These built-in commands are just ordinary Lisp functions whose names
 begin with @code{eshell/}.)  In order to call the external variant of
 a built-in command @code{foo}, you could call @code{*foo}.  Usually,
-this should not be necessary.  You can check what will be applied by
-the @code{which} command:
+this should not be necessary; if the Eshell version of a command
+doesn't support a particular option, it will automatically invoke the
+external command for you.
+
+Some built-in Eshell commands provide enhanced versions of regular
+Emacs Lisp functions.  If you want to call the regular Emacs Lisp
+version, you can write your command in Lisp form (@pxref{Invocation}).
+To call the regular version in command form, you can use
+@code{funcall} or @code{apply}, e.g.@: @samp{funcall #'compile "make all"}
+(@pxref{Calling Functions,,, elisp, GNU Emacs Lisp Reference Manual}).
+
+You can check what will be applied by the @code{which} command:
 
 @example
 ~ $ which ls
@@ -420,14 +430,19 @@ Built-ins
 @end example
 
 If you want to discard a given built-in command, you could declare an
-alias (@pxref{Aliases}).  Example:
+alias (@pxref{Aliases}).  For example:
 
 @example
-~ $ which sudo
-eshell/sudo is a compiled Lisp function in `em-tramp.el'.
-~ $ alias sudo '*sudo $@@*'
-~ $ which sudo
-sudo is an alias, defined as "*sudo $@@*"
+@group
+~ $ alias ls '*ls $@@*'
+~ $ which ls
+ls is an alias, defined as "*ls $@@*"
+@end group
+@group
+~ $ alias compile 'apply #''compile $*'
+~ $ which compile
+ls is an alias, defined as "apply #'compile $*"
+@end group
 @end example
 
 Some of the built-in commands have different behavior from their
-- 
2.25.1


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

* bug#65273: 30.0.50; [PATCH] Add a built-in Eshell 'compile' command
  2023-08-13 19:59 bug#65273: 30.0.50; [PATCH] Add a built-in Eshell 'compile' command Jim Porter
@ 2023-08-16 17:04 ` Jim Porter
  0 siblings, 0 replies; 2+ messages in thread
From: Jim Porter @ 2023-08-16 17:04 UTC (permalink / raw)
  To: 65273-done

On 8/13/2023 12:59 PM, Jim Porter wrote:
> There are already a few built-in Eshell commands that pop up a 
> compilation buffer when used interactively ("make" and the various 
> "grep" commands). This patch adds a new, generic "compile" built-in so 
> that it's easy for users to take advantage of this behavior for other 
> programs (e.g. running "cmake" or "configure").

Merged to master as 647bcec4f53, and closing this now.





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

end of thread, other threads:[~2023-08-16 17:04 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-08-13 19:59 bug#65273: 30.0.50; [PATCH] Add a built-in Eshell 'compile' command Jim Porter
2023-08-16 17:04 ` Jim Porter

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