;; 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)
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."
(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
--- /dev/null
+;;; 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