Shell (zsh) through Emacs? - emacs

I usually run emacs in a terminal to work.
I would like to run a shell inside a emacs window.
I've found the shell command, but I would like to run the zsh I usually
use inside (with my own configuration).
Is it possible?
EDIT : I succeeded to run zsh through Emacs, but the PS1 prompt isn't rendered.
How could I render it? I assume I actually only have the "default" emacs prompt.

Like #TeddyKoker 's link suggested, I did the following :
adding this file as exec-path-from-shell.el to my emacs personnal configuration directories :
;;; exec-path-from-shell.el --- Get environment variables such as $PATH from the shell
;; Copyright (C) 2012-2014 Steve Purcell
;; Author: Steve Purcell <steve#sanityinc.com>
;; Keywords: environment
;; Package-Version: 20141212.846
;; URL: https://github.com/purcell/exec-path-from-shell
;; Version: DEV
;; This file is not part of GNU Emacs.
;; This file 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.
;; This file 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 this file. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;; On OS X (and perhaps elsewhere) the $PATH environment variable and
;; `exec-path' used by a windowed Emacs instance will usually be the
;; system-wide default path, rather than that seen in a terminal
;; window.
;; This library allows the user to set Emacs' `exec-path' and $PATH
;; from the shell path, so that `shell-command', `compile' and the
;; like work as expected.
;; It also allows other environment variables to be retrieved from the
;; shell, so that Emacs will see the same values you get in a terminal.
;; If you use a non-POSIX-standard shell like "tcsh" or "fish", your
;; shell will be asked to execute "sh" as a subshell in order to print
;; out the variables in a format which can be reliably parsed. "sh"
;; must be a POSIX-compliant shell in this case.
;; Note that shell variables which have not been exported as
;; environment variables (e.g. using the "export" keyword) may not be
;; visible to `exec-path-from-shell'.
;; Installation:
;; ELPA packages are available on Marmalade and MELPA. Alternatively, place
;; this file on a directory in your `load-path', and explicitly require it.
;; Usage:
;;
;; (require 'exec-path-from-shell) ;; if not using the ELPA package
;; (exec-path-from-shell-initialize)
;;
;; Customize `exec-path-from-shell-variables' to modify the list of
;; variables imported.
;;
;; If you use your Emacs config on other platforms, you can instead
;; make initialization conditional as follows:
;;
;; (when (memq window-system '(mac ns))
;; (exec-path-from-shell-initialize))
;;
;; Alternatively, you can use `exec-path-from-shell-copy-envs' or
;; `exec-path-from-shell-copy-env' directly, e.g.
;;
;; (exec-path-from-shell-copy-env "PYTHONPATH")
;;; Code:
(defgroup exec-path-from-shell nil
"Make Emacs use shell-defined values for $PATH etc."
:prefix "exec-path-from-shell-"
:group 'environment)
(defcustom exec-path-from-shell-variables
'("PATH" "MANPATH")
"List of environment variables which are copied from the shell."
:type '(repeat (string :tag "Environment variable"))
:group 'exec-path-from-shell)
(defvar exec-path-from-shell-debug nil
"Display debug info when non-nil.")
(defun exec-path-from-shell--double-quote (s)
"Double-quote S, escaping any double-quotes already contained in it."
(concat "\"" (replace-regexp-in-string "\"" "\\\\\"" s) "\""))
(defun exec-path-from-shell--tcsh-p (shell)
"Return non-nil if SHELL appears to be tcsh."
(and shell (string-match "tcsh$" shell)))
(defun exec-path-from-shell--login-arg (shell)
"Return the name of the --login arg for SHELL."
(if (exec-path-from-shell--tcsh-p shell) "-d" "-l"))
(defcustom exec-path-from-shell-arguments
(list (exec-path-from-shell--login-arg (getenv "SHELL")) "-i")
"Additional arguments to pass to the shell.
The default value denotes an interactive login shell."
:type '(repeat (string :tag "Shell argument"))
:group 'exec-path-from-shell)
(defun exec-path-from-shell--debug (msg &rest args)
"Print MSG and ARGS like `message', but only if debug output is enabled."
(when exec-path-from-shell-debug
(apply 'message msg args)))
(defun exec-path-from-shell--standard-shell-p (shell)
"Return non-nil iff SHELL supports the standard ${VAR-default} syntax."
(not (string-match "\\(fish\\|tcsh\\)$" shell)))
(defun exec-path-from-shell-printf (str &optional args)
"Return the result of printing STR in the user's shell.
Executes $SHELL as interactive login shell.
STR is inserted literally in a single-quoted argument to printf,
and may therefore contain backslashed escape sequences understood
by printf.
ARGS is an optional list of args which will be inserted by printf
in place of any % placeholders in STR. ARGS are not automatically
shell-escaped, so they may contain $ etc."
(let* ((printf-bin (or (executable-find "printf") "printf"))
(printf-command
(concat printf-bin
" '__RESULT\\000" str "' "
(mapconcat #'exec-path-from-shell--double-quote args " ")))
(shell-args (append exec-path-from-shell-arguments
(list "-c"
(if (exec-path-from-shell--standard-shell-p (getenv "SHELL"))
printf-command
(concat "sh -c " (shell-quote-argument printf-command))))))
(shell (getenv "SHELL")))
(with-temp-buffer
(exec-path-from-shell--debug "Invoking shell %s with args %S" shell shell-args)
(let ((exit-code (apply #'call-process shell nil t nil shell-args)))
(exec-path-from-shell--debug "Shell printed: %S" (buffer-string))
(unless (zerop exit-code)
(error "Non-zero exit code from shell %s invoked with args %S. Output was:\n%S"
shell shell-args (buffer-string))))
(goto-char (point-min))
(if (re-search-forward "__RESULT\0\\(.*\\)" nil t)
(match-string 1)
(error "Expected printf output from shell, but got: %S" (buffer-string))))))
(defun exec-path-from-shell-getenvs (names)
"Get the environment variables with NAMES from the user's shell.
Execute $SHELL according to `exec-path-from-shell-arguments'.
The result is a list of (NAME . VALUE) pairs."
(let* ((dollar-names (mapcar (lambda (n) (format "${%s-}" n)) names))
(values (split-string (exec-path-from-shell-printf
(mapconcat #'identity (make-list (length names) "%s") "\\000")
dollar-names) "\0")))
(let (result)
(while names
(prog1
(push (cons (car names) (car values)) result)
(setq values (cdr values)
names (cdr names))))
result)))
(defun exec-path-from-shell-getenv (name)
"Get the environment variable NAME from the user's shell.
Execute $SHELL as interactive login shell, have it output the
variable of NAME and return this output as string."
(cdr (assoc name (exec-path-from-shell-getenvs (list name)))))
(defun exec-path-from-shell-setenv (name value)
"Set the value of environment var NAME to VALUE.
Additionally, if NAME is \"PATH\" then also set corresponding
variables such as `exec-path'."
(setenv name value)
(when (string-equal "PATH" name)
(setq eshell-path-env value
exec-path (append (parse-colon-path value) (list exec-directory)))))
;;;###autoload
(defun exec-path-from-shell-copy-envs (names)
"Set the environment variables with NAMES from the user's shell.
As a special case, if the variable is $PATH, then `exec-path' and
`eshell-path-env' are also set appropriately. The result is an alist,
as described by `exec-path-from-shell-getenvs'."
(mapc (lambda (pair)
(exec-path-from-shell-setenv (car pair) (cdr pair)))
(exec-path-from-shell-getenvs names)))
;;;###autoload
(defun exec-path-from-shell-copy-env (name)
"Set the environment variable $NAME from the user's shell.
As a special case, if the variable is $PATH, then `exec-path' and
`eshell-path-env' are also set appropriately. Return the value
of the environment variable."
(interactive "sCopy value of which environment variable from shell? ")
(cdar (exec-path-from-shell-copy-envs (list name))))
;;;###autoload
(defun exec-path-from-shell-initialize ()
"Initialize environment from the user's shell.
The values of all the environment variables named in
`exec-path-from-shell-variables' are set from the corresponding
values used in the user's shell."
(interactive)
(exec-path-from-shell-copy-envs exec-path-from-shell-variables))
(provide 'exec-path-from-shell)
;; Local Variables:
;; coding: utf-8
;; indent-tabs-mode: nil
;; mangle-whitespace: t
;; require-final-newline: t
;; checkdoc-minor-mode: t
;; End:
;;; exec-path-from-shell.el ends here
And adding the following in my ~/.emacs :
;; Set terminal :
(setenv "ESHELL" (expand-file-name "~/.emacs_config/scripts/eshell"))
(require 'exec-path-from-shell) ;; if not using the ELPA package
I still don't have access to all zsh features (like prompt expansion) but at least it works better. :)

Related

Spawing ctags from Emacs with start-process

I have a function that is supposed to create a ctags file and load it into Emacs asynchronously. ctags can take a while to run if invoked on really big files, and I don't want my function to do any blocking, thus I use start-process. This is what it all looks like:
(defun temp-tags-file-for-file (file)
"Generate a temporary tags file for FILE.
Add the file to tags list and return the name of the file."
(if (not (boundp 'ctags-command))
(setq ctags-command "/usr/bin/ctags"))
(let* ((temp-file (make-temp-file "EMACS_TAGS"))
(proc (start-process "temp-tags-proc" nil ctags-command
"-f" temp-file file)))
(set-process-sentinel proc
(lambda (proc msg)
(when (eq (process-status proc) 'exit)
(if (boundp 'temp-tags-file)
(progn
(add-to-list 'tags-table-list
temp-tags-file)
(makunbound 'temp-tags-file))))))
(setq temp-tags-file temp-file)
temp-file))
For some reason, the tags file is always blank. Calling ctags with the exact same parameters from the shell generates a non-blank, working tags file. How do I get ctags to print its output properly?
If ctags wants the shell, just give it to the shell:
(start-process "temp-tags-proc" nil shell-file-name shell-command-switch
(format "/usr/bin/ctags ~/Dropbox/source/c/*.c -f %s"
(make-temp-file "EMACS_TAGS")))

Run elisp program without Emacs?

elisp is a good language, I find it can handle all kind of jobs, but can I use it like a shell script?
i.e. execute some *.el files from the console, without launching Emacs. Or launch Emacs, but don't enter interactive mode.
You can most definitely run elisp scripts in Emacs without starting the editor interface.
Here are the notes I've made/copied from a few extremely useful Q&As on the subject here at S.O. (and the following two in particular).
Emacs shell scripts - how to put initial options into the script?
Idiomatic batch processing of text in Emacs?
Much of this information, and more besides, is also covered in the following excellent overview, which is recommended reading:
https://swsnr.de/blog/2014/08/12/emacs-script-pitfalls/
;;;; Elisp executable scripts
;; --batch vs --script
;; M-: (info "(emacs) Initial Options") RET
;; M-: (info "(elisp) Batch Mode") RET
;; Processing command-line arguments (boiler-plate)
;; http://stackoverflow.com/questions/6238331/#6259330 (and others)
;;
;; For robustness, it's important to both pass '--' as an argument
;; (to prevent Emacs from trying to process option arguments intended
;; for the script), and also to exit explicitly with `kill-emacs' at
;; the end of the script (to prevent Emacs from carrying on with other
;; processing, and/or visiting non-option arguments as files).
;;
;; #!/bin/sh
;; ":"; exec emacs -Q --script "$0" -- "$#" # -*-emacs-lisp-*-
;; (pop argv) ; Remove the "--" argument
;; ;; (setq debug-on-error t) ; if a backtrace is wanted
;; (defun stdout (msg &optional args) (princ (format msg args)))
;; (defun stderr (msg &optional args) (princ (format msg args)
;; #'external-debugging-output))
;; ;; [script body here]
;; Always exit explicitly. This returns the desired exit
;; status, and also avoids the need to (setq argv nil).
;; (kill-emacs 0)
;; Processing with STDIN and STDOUT via --script:
;; https://stackoverflow.com/questions/2879746/#2906967
;;
;; #!/bin/sh
;; ":"; exec emacs -Q --script "$0" -- "$#" # -*-emacs-lisp-*-
;; (pop argv) ; Remove the "--" argument
;; (setq debug-on-error t) ; if a backtrace is wanted
;; (defun stdout (msg &optional args) (princ (format msg args)))
;; (defun stderr (msg &optional args) (princ (format msg args)
;; #'external-debugging-output))
;; (defun process (string)
;; "Reverse STRING."
;; (concat (nreverse (string-to-list string))))
;;
;; (condition-case nil
;; (let (line)
;; (while (setq line (read-from-minibuffer ""))
;; (stdout "%s\n" (process line))))
;; (error nil))
;;
;; ;; Always exit explicitly. This returns the desired exit
;; ;; status, and also avoids the need to (setq argv nil).
;; (kill-emacs 0)
Emacs aside, the only other elisp interpreter/compiler I'm aware of is Guile. If you're keen on general coding in elisp, that should be worth a look (especially if performance is a concern).

Using Emacs, is it possible to pin the compilation command to a specific buffer/directory?

Right now I am using the following to compile, when I'm in for example main.cpp
C-x b Makefile RET M-x compile RET RET
I actually have M-x compile as a keyboard shortcut, but the problem is I would really like not having to go through all that trouble to simply run my Makefile.
I need to visit Makefile to make sure the compile command is executed using the same directory. Is there any way to pin the directory so I can simply go M-x compile RET RET?
Best regards
Use recompile instead. C-u M-x recompile will let you edit the compile command first. Either way the compile will work out of the directory the last compile was done in.
See my answer here
Directory local variables provide an easy way to trigger the compile from a parent directory of any source file in a subdirectory.
I run emacs primarily on windows.
When I have a makefile that is in a parent directory of a C module, I use this as the compile command:
cd .. && nmake <arguments here>
for example:
cd .. && nmake CONFIG=Debug PLATFORM=x64 target
Beyond that, I find that specifying the make command line that I want to run for various modules is sort of a pain. I wanted a way to attach the default compile command to the buffer being edited. So I wrote a little elisp to handle that job. I figured to insert into the header comments of each buffer a line that would stipulate my preferred compile command, like this:
compile: cd .. && nmake CONFIG=Debug PLATFORM=x64 target
And then have a piece of elisp run, before I invoke M-x compile that grabs the line and proposes it as the compile command I would like to run.
This defun pulls a line out of the header comments:
(defun cheeso-c-get-value-from-comments (marker-string line-limit)
"gets a string from the header comments in the current buffer.
This is used to extract the compile command from the comments. It
could be used for other purposes too.
It looks for \"marker-string:\" and returns the string that
follows it, or returns nil if that string is not found.
eg, when marker-string is \"compile\", and the following
string is found at the top of the buffer:
compile: cl.exe /I uthash
...then this command will return the string
\"cl.exe /I uthash\"
It's ok to have whitespace between the marker and the following
colon.
"
(let (start search-limit found)
;; determine what lines to look in
(save-excursion
(save-restriction
(widen)
(cond ((> line-limit 0)
(goto-char (setq start (point-min)))
(forward-line line-limit)
(setq search-limit (point)))
((< line-limit 0)
(goto-char (setq search-limit (point-max)))
(forward-line line-limit)
(setq start (point)))
(t ;0 => no limit (use with care!)
(setq start (point-min))
(setq search-limit (point-max))))))
;; look in those lines
(save-excursion
(save-restriction
(widen)
(let ((re-string
(concat "\\b" marker-string "[ \t]*:[ \t]*\\(.+\\)$")))
(if (and start
(< (goto-char start) search-limit)
(re-search-forward re-string search-limit 'move))
(buffer-substring-no-properties
(match-beginning 1)
(match-end 1))))))))
Ok, now I need something to invoke that before I invoke compile.
(defun cheeso-invoke-compile-interactively ()
"fn to wrap the `compile' function. This simply
checks to see if `compile-command' has been previously set, and
if not, invokes `cheeso-guess-compile-command' to set the value.
Then it invokes the `compile' function, interactively."
(interactive)
(cond
((not (boundp 'cheeso-local-compile-command-has-been-set))
(cheeso-guess-compile-command)
(set (make-local-variable 'cheeso-local-compile-command-has-been-set) t)))
;; local compile command has now been set
(call-interactively 'compile))
Then of course, the defun that guesses the compile command:
(defun cheeso-guess-compile-command ()
"set `compile-command' intelligently depending on the
current buffer, or the contents of the current directory."
(interactive)
(set (make-local-variable 'compile-command)
(cond
(buffer-file-name
(let ((filename (file-name-nondirectory buffer-file-name)))
(cond
;; editing a C-language source file - check for an
;; explicitly-specified command
((string-equal (substring buffer-file-name -2) ".c")
(let ((explicit-compile-command
(cheeso-c-get-value-from-comments "compile" 34)))
(or explicit-compile-command
(concat "nmake " ;; assume a makefile exists
(file-name-sans-extension filename)
".exe"))))
;; editing a makefile - just run nmake
((string-equal (substring buffer-file-name -8) "makefile")
"nmake ")
;; something else - do a typical .exe build
(t
(concat "nmake "
(file-name-sans-extension filename)
".exe")))))
(t
;; punt
"nmake "))))
The final bit is to bind C-x C-e , normally bound to compile, to the wrapper defun:
(global-set-key "\C-x\C-e" 'cheeso-invoke-compile-interactively)
Now, when I do C-x C-e in the buffer, it searches for the compile command, and proposes to me the command that it finds. I can edit the proposed compile command, then press ENTER and run it.

Why is my term-mode-hook not selecting line mode?

I wrote this elisp function:
(defun run (command)
"Open a terminal running a command."
(interactive "sCommand: ")
(if (buffer-exists (concat "*" command "*" )) (kill-buffer (concat "*" command "*")))
(let ((term-mode-hook (cons (lambda () (term-line-mode)) term-mode-hook)))
(ansi-term (cons "sh" (cons "-i" (list "-c" command))) command)))
This works nicely except that the new ansi-term buffers remains in char mode (which is the default), so as far as I can tell the term-line-mode call is not doing anything. If I replace (term-line-mode) with (message "foo") I do see the message in the messages buffer.
The definition of term-line-mode in lisp/term.el is:
(defun term-line-mode ()
"Switch to line (\"cooked\") sub-mode of term mode.
This means that Emacs editing commands work as normally, until
you type \\[term-send-input] which sends the current line to the inferior."
(interactive)
(when (term-in-char-mode)
(use-local-map term-old-mode-map)
(term-update-mode-line)))
What am I doing wrong?
I wasn't able to get "term-line-mode" to work as you want in any of the term hooks; however, it does work if you advise the "ansi-term" function:
(defadvice ansi-term (after advice-term-line-mode activate)
(term-line-mode))

emacs equivalent of following vi command

I am looking for equivalent of following vi command
:! nl %
this runs nl command on currently open file
What is emacs way to detect name of open file ?
M-X shell-commnad nl
I am not able find determine value of current open/buffer and substitute.
Thx/Mahesh
EDIT: Misread your question as wanting to apply that change to the file you're working on. If you just want to run a shell command against a buffer, you can use shell-command-on-region, which is usually bound to M-|.
If you're just trying to get to a particular line number, M-x goto-line works. I bind that to C-x C-l by putting (define-key global-map "\C-x\C-l" 'goto-line) in my ~/.emacs.
Try this (in your ~/.emacs file):
;;; Run a shell command on all text between the mark and the point and
;;; replace with the output.
(defun shell-command-in-region (start end command &optional flag interactive)
"Execute shell-command-on-region and replace the region with the output
of the shell command."
(interactive (list (region-beginning) (region-end)
(read-from-minibuffer "Shell command in region: "
nil nil nil 'shell-command-history)
current-prefix-arg
(prefix-numeric-value current-prefix-arg)))
(shell-command-on-region (point) (mark) command t)
)
(define-key esc-map "#" 'shell-command-in-region)
Invoke it by selecting a region you want to operate on and then doing M-#.
If you always want the buffer's file name to be inserted for the shell command, you can use this advice:
(defadvice read-shell-command (before read-shell-command-with-filename activate)
"force the initial contents to contain the buffer's filename"
(if (and (null (ad-get-arg 1))
buffer-file-name)
(ad-set-arg 1 buffer-file-name)))
Once you've added the above code, M-x shell-command will always start with the buffer's file name, so you can use it in the command.
I use this:
(defun my-shell-command-on-current-file (command &optional output-buffer error-buffer)
"Run a shell command on the current file (or marked dired files).
In the shell command, the file(s) will be substituted wherever a '%' is."
(interactive (list (read-from-minibuffer "Shell command: "
nil nil nil 'shell-command-history)
current-prefix-arg
shell-command-default-error-buffer))
(cond ((buffer-file-name)
(setq command (replace-regexp-in-string "%" (buffer-file-name) command nil t)))
((and (equal major-mode 'dired-mode) (save-excursion (dired-move-to-filename)))
(setq command (replace-regexp-in-string "%" (mapconcat 'identity (dired-get-marked-files) " ") command nil t))))
(shell-command command output-buffer error-buffer))
(global-set-key (kbd "M-!") 'my-shell-command-on-current-file)
Then you can do M-! nl %