need help writing an emacs function - emacs

I want to write an emacs function that does the following -
1) Start a new shell named "abc".
2) Change the dir "/opt/abc"
3) In the dir run a shell command "python abc.py"
I have written the following function -
(defun abc-server ()
(interactive)
(shell-command "cd /opt/abc/")
(shell-command "python abc.py"))
The problem with the above -
1) It doesnt start a new shell
2) It doesnt change the dir.
3) When the cmd executes, it opens a browser window, which completely blocks any usage of emacs.

From shell-command's docstring (C-h f shell-command):
If COMMAND ends in ampersand, execute it asynchronously.
The output appears in the buffer `Async Shell Command'.
That buffer is in shell mode.
Also, combine it all into one command line. shell-command makes a new shell every time, so the pwd will not persist from one invocation to another.
(defun abc-server ()
(interactive)
(shell-command "cd /opt/abc/; python abc.py &"))

While #jpkotta's answer is good enough, a proper solution would use the anync primitives of Emacs. For one thing, you can only have one async shell command running at a time, whereas you can have a large number of named subprocesses.
(defun abc-server ()
(interactive)
;; Create buffer ahead of time so we can change its default directory
(save-excursion
(get-buffer-create "*abc-server*")
(cd "/opt/abc") )
(start-process "abc" "*abc-server*" "python" "abc.py") )
(I'm not altogether happy with the save-excursion hoop. I was hoping I could simply let-bind default-directory, but that didn't seem to work as I had expected. Alternatively, you could (start-process "abc" "*abc-server*" "sh" "-c" "cd /opt/abc; python abc.py").)
If you need to extend the command further, I would argue that this is a more scalable platform than the quick and dirty async shell command approach, but if this is all you are ever going to need, it doesn't matter much.

Related

In emacs, what is the best way to run an external program in another window that can be closed by a single key command after executing program exits?

I have some elisp that runs an external 'npm' command.
(defun npm-mode-npm-run ()
"Run the 'npm run' command on a project script."
(interactive)
(let ((command
(completing-read
"Run command: " (npm-mode--get-project-scripts))))
(message "Running npm script: %s" command)
(switch-to-buffer npm-mode--buffer-name command)
(erase-buffer)
(ansi-term (getenv "SHELL") "npm-mode-npm-run")
(comint-send-string "*npm-mode-npm-run*" (format "npm run-script %s\n" command))))
While it does the job, when execution completes the user is left in a buffer that must be killed, and that requires additional confirmation to kill the process.
What I would like is once the program exits, I could press the 'q' key to do all of that, leaving the user in their original buffer.
Is their a good example of how to do this best for modern emacs that I could refer to, or any other specific docs that may be helpful?
Many thanks in advance!
As #jpkotta said, compile is a good option. You can bury the buffer easily, send a TERM signal to the underlying process, etc. Also, you get for free error parsing (syntax coloring + the ability to jump to the offending line) for many languages.
Here is an example of how I use it (in this case to do a quick run of any script I am editing):
(defun juanleon/execute-buffer ()
(interactive)
(let ((compile-command nil))
(compile buffer-file-name)))
Easy to modify to adapt to your code. The let is for avoid adding stuff to compile history (since I use compile a lot for regular compilation, and history is useful).

How can the *shell command output* buffer be kept in the background?

How can I tell emacs not to pop up the *Shell Command Output* buffer when calling a shell command like this?
(shell-command MY_COMMAND)
Currently emacs splits the current window into two, showing the (mostly irrelevant) output buffer. To me it would be completely sufficient if I could look it up later if I feel like it.
Maybe using shell-command was the root of the problem. I think I found a solution with call-process which works, although there may be a more elegant way:
(call-process-shell-command
"cat ~/.emacs.d/init.el"
nil "*Shell Command Output*" t
)
shell-command takes an optional argument OUTPUT-BUFFER where you can specify the buffer to output to. If it is t (actually not a buffer-name and not nil) it will be output in the current buffer. So we wrap this into a with-temp-buffer and will never have to bother with it:
(with-temp-buffer
(shell-command "cat ~/.emacs.d/init.el" t))
In my experience, if the shell command itself produces no output, then the emacs *Shell Command Output* buffer won't pop open.
Therefore, to avoid the output buffer, silence the output of the command.
One easy way is:
add " > /dev/null 2>&1" to the end of any shell command.
(Caveat: I'm unsure if /dev/null exists on 100% of platforms where one can run emacs, but on every Linux distro it should be fine.)
If the call to elisp function shell-command is in an elisp script, then you could change this:
(shell-command cmd)
to this:
(shell-command (concat cmd " > /dev/null 2>&1"))
If you occasionally do want to monitor the output, then you could create one wrapper function that suppresses the output via /dev/null, and one wrapper function with no suppression, and toggle between them as you wish.
The above advice was tested on: GNU Emacs 24.5.1 (x86_64-pc-linux-gnu, GTK+ Version 3.18.9) of 2017-09-20 on lcy01-07, modified by Debian
This utility function might help. It returns the actual value of the shell command
(defun shell-command-as-string (cmd)
(with-temp-buffer
(shell-command-on-region (point-min) (point-max)
cmd t)
(buffer-string)))
What's even better, is to use
(shell-command (concat cmd " 1>&2") t t)
This way, the output is saved in the error buffer, should you want to look at it. But it does not pop up automatically.

How do I define an Emacs Lisp function to spawn a shell buffer with a particular command executed in the shell?

I am doing Rails development and find that I need to spawn a shell, rename the buffer (e.g. webrick), then kick off the command (rails s) and then do the whole thing over again if I want a rails console or rails dbconsole, rspec, spork, etc. every time I start up emacs.
I am hoping for something like this:
(defun spawn-shell ()
"Invoke shell test"
(with-temp-buffer
(shell (current-buffer))
(process-send-string nil "echo 'test1'")
(process-send-string nil "echo 'test2'")))
I don't want the shell to go away when it exits because the output in the shell buffer is important and some times I need to kill it and restart it but I don't want to lose that history.
Essentially, I want to take the manual process and make it invokable.
Any help is much appreciated
Tom
Perhaps this version of spawn-shell will do what you want:
(defun spawn-shell (name)
"Invoke shell test"
(interactive "MName of shell buffer to create: ")
(pop-to-buffer (get-buffer-create (generate-new-buffer-name name)))
(shell (current-buffer))
(process-send-string nil "echo 'test1'\n")
(process-send-string nil "echo 'test2'\n"))
It prompts for a name to use when you run it interactively (M-x spawn-shell). It creates a new buffer based on the input name using generate-new-buffer-name, and you were missing the newlines on the end of the strings you were sending to the process.
If your only problem is that the shell buffer disappears after the commands have been executed, why not use get-buffer-create instead of with-temp-buffer?

How can I reload the interactive shell and run some commands on emacs startup?

I relise that I have to add something like:
shell
: to my .emacs file. But then how can I get it to do shell commands like:
cd /mydirectory
: and other shell actions
This is a function which does what you want. You can add it (customizing the actions), or just add the body:
(defun shell-and-stuff ()
"run a shell, then do some extra stuff"
(interactive)
(let ((shell-buf (get-buffer-create "*shell*")))
(shell shell-buf)
(comint-send-string
(get-buffer-process shell-buf)
"cd some-directory
ls
touch frog
")))
(shell-and-stuff)
The cd part is easy, just let bind the variable default-directory. See this question for some possible solutions.
Trey Jackson's idea looks good. Also note that the manual (info "(emacs) Interactive Shell") says
Emacs sends the new shell the contents of the file
~/.emacs_SHELLNAME as input, if it exists, where SHELLNAME is the
name of the file that the shell was loaded from. For example, if you
use bash, the file sent to it is ~/.emacs_bash. If this file is not
found, Emacs tries to fallback on ~/.emacs.d/init_SHELLNAME.sh.
So you could put your commands in that file.

which shell-command in emacs lisp?

If I am trying to run a shell-command in an Emacs Lisp function in which I call rsync (or scp) multiple times, which shell-command variant should I use? I am currently using shell-command, which locks up Emacs until the process is done, and the output that should be visible with the --verbose to rsync is not printed; I can use shell-command with an & at the end of the command string to make it asynchronous, which does print the progress — but while it doesn't "lock up" Emacs entirely, the minibuffer repeatedly asks if I want to kill the process which is crippling in the meantime; and start-process-shell-command, which appears to halt the function only after the first file/directory is transferred; neglecting the rest when there are multiple rsync calls made through my function. None of these seem ideal, any hints?
I have had the most success using start-process myself.
(start-process "process-name"
(get-buffer-create "*rsync-buffer*")
"/path/to/rsync"
arg1
...
argn)
This will send all the output to a single buffer.
One solution might be to run the command in an actual shell buffer. Then you get to choose which one of those to run:
M-x shell
M-x eshell
M-x term
If you like that idea, you can code it up like this:
(defun my-rsync-routine ()
"run some rsync processes"
(with-temp-buffer
(shell (current-buffer))
(process-send-string nil "rsync ...")
(process-send-string nil "rsync ...")
(process-send-string nil "rsync ...")))
Read more on 'process-send-string for its usage. You might also want to have some error checking on the output from the processes.