* 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 external index
https://git.savannah.gnu.org/cgit/emacs.git
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.