Can I use bash autocomplete when editing shell scripts in emacs? - bash

In my environment, I have bash autocomplete set up to do lots of amazing things.
However, when I'm editing a shell script in emacs, all of that autocomplete magic goes away.
Is there any way to get emacs to do bash command line autocompletion when I'm editing shell scripts?
I would accept an answer that requires me to use a different editor, if that editor were available on Linux systems. I would also accept an answer that tells me that I need to use a different shell's autocomplete.

bash-completion.el provides an interface to normal bash completion, which can also be extended to work in normal sh-modes with an addition to your completion-at-point-functions. Here is how that could work, just using the command sh-beginning-of-command from sh-script to determine the current completion candidate (this could be extended to handle more complicated shell commands if necessary).
(require 'sh-script) ;sh-beginning-of-command
(require 'bash-completion)
(defun my-sh-completion-at-point ()
(let ((end (point))
(beg (save-excursion (sh-beginning-of-command))))
(when (and beg (> end beg))
(bash-completion-dynamic-complete-nocomint beg end t))))
(defun my-sh-hook ()
(add-hook 'completion-at-point-functions #'my-sh-completion-at-point nil t))
(add-hook 'sh-mode-hook #'my-sh-hook)

Related

Sending bash commands to an open terminal buffer in emacs

I've been trying to improve my emacs life lately, and one thing I've done is make use of projectile and perspective to organize my buffers sensibly.
As part of this I wrote an elisp function to open up (or return to) a named ansi-term buffer that is project-specific. This allows me to quickly drop into a bash terminal for the project I'm currently looking at.
What I have been having trouble finding out after plumbing the interwebs is whether or not it is possible to send bash commands to an open ansi-term buffer from within emacs. Specifically, I'm trying to make sure the ansi-term buffer cds to the correct project root directory when it's first opened. This requires grabbing context from the projectile package first, so it's not something I can plop into my .bashrc.
Ideally I would be able to write an elisp function that:
1) selects an ansi-term buffer by name (since I can have one open with a unique name for every project)
2) sends and executes a command in that buffer
Is there any way to do this?
EDIT
Final solution for anyone who is interested:
(defun visit-project-term-buffer ()
"Create or visit a terminal buffer."
(interactive)
(if (not (get-buffer (persp-ansi-buffer-name)))
(progn
(split-window-sensibly (selected-window))
(other-window 1)
(ansi-term (getenv "SHELL"))
(rename-buffer (persp-ansi-buffer-name))
(end-of-buffer)
(insert (format "cd %s" (projectile-project-root)))
(term-send-input))
(switch-to-buffer-other-window (persp-ansi-buffer-name))))
Does this work for you? It switches to a buffer named *terminal* and runs echo hello:
(defun my-echo ()
(interactive)
(switch-to-buffer "*terminal*")
(end-of-buffer)
(insert "echo hello")
(term-send-input))

Emacs how to run command in Interactive command line mode in elisp

I am newbie to Emacs.
I want to define a function in elisp to run a command in interactive command line mode (Asynchronously if possible).
my current code is:
(defun ma () ;run maxima batch on the current file
(interactive)
(let*
((fn (buffer-file-name)) (cmd (concat "maxima -b " fn)))
(message "cmd:%s" cmd)
(shell-command cmd)
)
)
this works fine when I do not have break points in the maxima code. When I have break points "break()", I have to interact with the program. The current shell-command function does not work.
I also like the mechanism of "shell-command" function that the screen will automatically split into two and show the programming running info in a second window. If possible, I still want this feature in the code that you can help me with.
Any help would be appreciated.
I want to define a function in elisp to run a command in interactive
command line mode (Asynchronously if possible).
Maybe async-shell-command is what you are looking for do C-h f async-shell-command RET for help on the function.
Use the built in compile function in commint mode.
(defun ma (&optional filename)
(interactive)
(compile (format "maxima -b %s" (or filename (buffer-file-name))) t))
This will open up a new window and will show you the output of the program running. Commint mode means that the compilation process is interactive, you will be able to send input to the program from the compilation buffer.

How to trigger or instrument with edebug programmatically?

C-u C-M-x evaluates a defun form with edebug instrumented. Can I do that programmatically? I want to do that because I want to write an elisp file of the following form:
;;; define a function with edebug instrumented.
...
;;; do something that invokes the function with particular arguments.
...
then I can run emacs -q --load on that elisp file, step through code, get an idea on further investigation on the bug, edit the elisp file in my original emacs session, run emacs -q --load on it again, and repeat.
In ~/test.el:
(defun square (x)
(* x x))
In ~/testtest.el:
(with-current-buffer (find-file-noselect "~/test.el")
(re-search-forward "square")
(edebug-defun))
(square 5)
In bash:
emacs -q -l ~/testtest.el

Reading command-line arguments in MIT-scheme

I am trying to run a scheme program using MIT-scheme (MIT/GNU Scheme running under GNU/Linux, Release 7.7.90.+ || Microcode 15.1 || Runtime 15.7) and I would like to access the command-line arguments.
I have looked in the documentation but I haven't found anything specific.
I have tried command-line, but I get an error message:
;Unbound variable: command-line
Do I have to load some library in order to use command-line, or is there some other function for this?
I have managed to find the following solution.
I have created a file init.scm with the following definitions:
(define command-line-args '())
(define parse-argument-list
(lambda (arg-list)
(set! command-line-args
(if (null? arg-list)
(list)
(cdr arg-list)))))
(set-command-line-parser! "args" parse-argument-list)
In this way, when the command line option --args is found, the function
parse-argument-list is invoked.
I have loaded this file into the mit-scheme interpreter and saved a world image
(init.com) using the procedure disk.save.
I have then written a shell script (bash) that invokes my main Scheme script as follows:
mit-scheme --band "init.com" --interactive --batch-mode --args $* < myscript.scm
Finally, in my main script I can access the command line arguments through the variable
command-line-args
I am not sure whether this is the standard / correct way to do this but at least it works.

Multiple asynchronous shell-commands in Emacs-Dired?

Emacs obviously can handle multiple asynchronous sub-processes, otherwise a multi-language programming environment like org-babel, to give an example, wouldn't be possible.
However, when I'm in Dired and start an asynchronous shell command to view a pdf file (& evince), and then try to do the same on a second pdf file, I get the following message:
"A command is running - kill it? Yes or No?"
Is there a way to run several asynchronous shell commands in parallel, when in Dired?
When you use dired-do-async-shell-command Emacs create a *Async Shell Command* buffer. If you want another async command you need to rename this buffer, for example using M-x rename-uniquely
you could try to change the comportment of dired-do-async-shell-command by advising it:
(defadvice shell-command (after shell-in-new-buffer (command &optional output-buffer error-buffer))
(when (get-buffer "*Async Shell Command*")
(with-current-buffer "*Async Shell Command*"
(rename-uniquely))))
(ad-activate 'shell-command)
note that I really advice the shell-command Emacs command because it's called by dired.
I don't think it's possible with dired-do-async-shell-command, but if you just want to open some file is certain external application I suggest using OpenWith, which allows any number of external processes running.
I've just setup the following which erases the current definition of dired-run-shell-command to pass a dedicated buffer name to shell-command:
(defun dired-run-shell-command (command)
(let ((handler
(find-file-name-handler (directory-file-name default-directory)
'shell-command)))
(if handler (apply handler 'shell-command (list command))
(shell-command command
(generate-new-buffer-name
(concat "*Shell Command Output: '" command "'*")))))
;; Return nil for sake of nconc in dired-bunch-files.
nil)

Resources