Equivalent of "exec" in emacs *eshell*? - emacs

I want to write an eshell function that sort of wraps an existing command-line script. In order to do this, I want to be able to execute a shell command from an eshell function. My first instinct was to do something like
(defn eshell/myfunc ()
(shell-command "mycommand"))
And this sort of works, except for a few problems. It runs in an inferior shell instead of behaving like a real "exec" command. This means that, among other things, the command "myfunc" in eshell appears to block while the command is running. The output of "mycommand" is collected an appears in a Shell Output buffer at the end, but it doesn't replicate the behavior of a normal shell function, where the standard output appears while it runs.
So, what's the correct way to do this?

Try
(start-process-shell-command "foo" (current-buffer) "mycommand")
If you need more control, see Emacs Lisp Referece Manual, Sectioin 37.4 Creating an Asynchronous Process.

Related

Emacs execute process continuously

There's a way to launch a process(continuously) in emacs?
For example, imagine ruby REPL, I expect launch the command "irb" in emacs and it should be in some some kinda of separated tab or buffer.
For the specific case of REPLs in Spacemacs you can start one for any supported language with SPC m s i then explore SPC m s prefix command for all the commands to interact with the REPL.
M-x shell
irb
This will cover simple use cases. To get previous commands, type M-p and M-n instead of up and down.
You can get a fancier version from #legoscia's link.
Can also do M-! to execute a single shell command and output to a new buffer.

Get tab completion in custom comint mode

I usually try to start CLI's (might not be defining it properly) using commands like:
(make-comint-in-buffer "PUTTY" nil "./plink.exe" nil "dbserver")
(make-comint-in-buffer "Python" nil "c:/Python26/python.exe" nil "-i")
(make-comint-in-buffer "Python" nil "c:/Python27/python.exe" nil "-i")
(make-comint-in-buffer "git" nil "C:/Program Files (x86)/Git/bin/sh.exe" nil "--login" "-i")
Starting the above specially the first and the last in command prompt provides the facility of tab completion. But in comint-mode I don't seem to get this feature.
Entering tab adds a simple tab character under the point instead of passing it to the process and getting back the completion candidates. comint-dynamic-complete and C-qtab doesn't produce the desired result.
How can I utilize in above said feature in comint-mode running different processes?
Short answer
You need to write your own completion functions inside Emacs. These may pull info in from the external program, but you can't have direct access to the tab-completion provided by python or git etc.
Long answer:
When you run make-comint-in-buffer, you are setting up the most basic setup for interactively sending and receiving data from an external process. Whenever you press enter, Emacs sends the current line to the underlying process, and then prints back the output from the process. The external process doesn't know what you're doing until Emacs sends a full line to it - no single characters are passed directly.
This is different from running the external program directly in a terminal. When you run python in a terminal, it interprets every character as you type it (or at least it can). So when you hit tab it knows to try to complete something. When you run python inside Emacs, Emacs is processing all of your input until you hit enter. Which means when you hit tab, Emacs just inserts a tab character, and python doesn't know to try and complete something.
Emacs can provide tab-completion for comint modes, but you need to build the completion targets on the Emacs side, you can't rely on the native completion of the external program. To get an idea of how this works, take a look at the completion functions in shell.el, which you can open with M-x find-library shell.
This isn't something you can do with a line or two of elisp. It's an important part of major-modes written to interact with external processes - things like ESS for R http://ess.r-project.org/
That said, if you dig into the guts of shell.el you may find enough code you can modify to get you started.

Tab completion, rlcompleter in Emacs

I have a Python program which uses rlcompleter to provide custom Tab-completion. The completion works when it is run under a bash terminal. However, it does not work under emacs, in shell mode, nor in eshell mode.
I noticed that Tab is really bound to completion-at-point, eshell-pcomplete, and so on, so I tried an (insert "\t"), supposing that this would trigger the completion, which I understand happens when the child process reads a "\t" character. But this does not work either. Perhaps input is buffered until a "RET"?
Completion for commands like service, which define their own candidates, does not work as expected either.
How can I access these candidates within Emacs?
Try using M-x ansi-term. I find it behaves a bit more like what I have come to expect from a *nix terminal.

Properly invoking an interactive script from elisp

I have an external command line program that I would like to invoke from elisp. This is easy enough with shell-command, but it doesn't work correctly when the command line program is interactive, which in my particular case it is: The invoked script sees EOF when it reads stdin when I call it like this:
;; upload command is a string with the name of
;; a python script and some args
(shell-command upload-command
(get-buffer-create "*upload output*")))))
The python script identified by upload-command may ask some yes/no questions and it may prompt for a password, for which I'd like masked input. Ideally, all of this interaction would occur within the minibuffer.
How can I arrange things so that my external interactive command interacts with the user via minibuffer when called via elisp?
The easiest way is to use either make-comint or make-comint-in-buffer:
(make-comint-in-buffer "upload-script-process" "*upload output*" upload-command)
This will runs the script in a buffer like a shell buffer, so it doesn't fulfill the requirement of having all interaction happen in the minibuffer. It will, however, automatically read passwords in masked form from the minibuffer, provided the password prompt matches comint-password-prompt-regexp.
Note that upload-command in this example here needs to be the name of an executable file on exec-path. Any extra switches or other arguments to the script have to be passed as string arguments to make-comint:
(make-comint-in-buffer "upload-script-process" "*upload output*"
upload-command nil "--verbose" "--other-option")
See the Emacs documentation for more details.

Can Emacs run command in background

I have an Emacs command like following:
(defun query-lisp (word)
(interactive "sType a word to query:")
(message "%s" (query word)))
The query operation is a time-consuming operation. When this command is running Emacs blocks the whole frame. Is there a way to make Emacs run this command in the background or block only a single window such as the minibuffer?
If you plan to use an external process (which you have indicated in a comment to another question), you can use the following:
(start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS)
This will return a process object. You can either send the output to a buffer, or you could attach a filter function to the process. In the latter case, this is a function that is called every time your process emits any output.
In addition, you could attach a sentinel function to your process. This function is called everytime the status of your process changes, this is useful to find out when it has exited.
There are several examples of the above in the source code of Emacs, one such example is compile.el.
Emacs doesn't have threads. For long operations you can split up the task into chunks and execute the chunks in idle timers, so emacs can respond to user input between the chunks.
The other possibility is running it as an external process from which emacs accepts the output.
For example, you can use something like this
(shell-command "sleep 10 && echo 'finished' &")
The result will be displayed in *Async Shell Command* buffer.