Emacs: run shell command with regex and Lisp function to start gud - emacs

I am tring to write some Emacs Lisp function to be able to simply compile and debug Java classes within Spacemacs using its Java layer (don't want to go into complex packages like jdee). The compile function is defined beblow and works as expected
(defun my-java-compile (command)
(interactive (list (read-string
"Command: "
(concat
"javac"
" -d "
java-dest-path
" -cp "
java-class-path
" "
(file-name-nondirectory buffer-file-name)))))
(unless (file-exists-p java-dest-path)
(make-directory java-dest-path))
(compilation-start command nil)
)
The java-dest-path and java-class-path are local variables set in the .dir-locals.el in the root directory of the project.
The debug function is defined as:
;; get fully qualified class name
(defun get-fqcn ()
(setq get-package-name-command
(concat
"gsed -n 's/^package\s\+\([^;\s]\+\);\s*$/\1/p' "
buffer-file-name))
(setq fqpn (shell-command-to-string get-package-name-command))
(if (equal "" fqpn) (file-name-base buffer-file-name)
(concat fqpn "." (file-name-base buffer-file-name)))
)
(defun my-jdb (command)
(interactive (list (read-string
"Command: "
(concat
"jdb"
" -classpath "
java-class-path
" "
(get-fqcn)))))
(helm-M-x nil jdb command)
)
I am still trying to make it work. Here are the two issues:
when running shell-command-to-string function, the gsed -n
's/^package\s\+\([^;\s]\+\);\s*$/\1/p' java_file command returns an empty
string "", while it returns the fully qualified package name as
expected when running in a terminal. If I change it to gsed -n '/^package/p', the emacs function return the package line OK. So
it seems shell-command-to-string could not handle the regular
expression in gsed. Any work around?
I could not find the function to trigger the gud or jdb . What would be the gud equivalent of compilation-start function?

The problem is that you want to include backslashes in your regexp, but backslashes are already used as escape characters in Emacs Lisp strings. Let's try displaying the string in the echo area:
(message "%s" "gsed -n 's/^package\s\+\([^;\s]\+\);\s*$/\1/p' ")
This displays:
gsed -n 's/^package +([^; ]+); *$/^A/p'
So as you can see, the backslashes were "eaten" by the Emacs Lisp parser. We need to double the backslashes in order for them to appear literally in the string we send to gsed:
"gsed -n 's/^package\\s\\+\\([^;\\s]\\+\\);\\s*$/\\1/p' "
Alternatively, implement the search in Emacs Lisp:
(save-excursion
(goto-char (point-min))
(search-forward-regexp "^package[[:blank:]]+\\([^;[:blank:]]+\\);")
(match-string 1))
The function for running jdb inside gud is jdb:
(jdb command)

Related

how to specify multiple file extensions in rgrep?

I tried *.{cc,hh} but it doesn't work (this works for lgrep though). i also tried the method suggested her e http://compgroups.net/comp.emacs/searching-multiple-file-types-with-rgrep/95027 but it seems the interactive mode doesn't allow me to input space. Any idea?
*.cc *.hh is correct. The find command will then use something like:
\( -iname \*.cc -o -iname \*.hh \)
(If you supply a prefix argument, you can view/edit the command before it is executed.)
You can enter the space using quoted-insert: C-qSPC, or just-one-space: M-SPC
I was (in despair) rolling an elisp solution:
(defun mrgrep (pattern extensions dir)
(interactive "ssearch for: \nsextensions (space separated, no *): \nD")
(setq includes (mapconcat (lambda (ext)
(concat (format "--include=\"\\*%s\"" ext)))
(s-split " " extensions)
" "))
(setq cmd (format "grep -ir %s %s %s"
includes
pattern
(concat dir "*")))
(setq cmd (read-from-minibuffer "run grep like this: " cmd))
(compilation-start cmd 'grep-mode)
)
but phils explained how to enter the space !

One-shot command to knit and latexmk under Emacs + AUCtex

I want to knit AND latexmk Knitr documents using one AUCtex command.
I don't know how to code in lisp, and web search didn't turn up anything like this.
I have something close. The extension of the file needs to be changed for latexmk.
Any help will be appreciated.
Following line is for my .emacs file.
(add-hook 'LaTeX-mode-hook (lambda () (push '
("KnitrLaTeX" "Rscript -e \"library(knitr)\; knit('%s')\" && latexmk -pdf %s"
TeX-run-TeX nil t :help "Run knitr and latexmk on file")
TeX-command-list)))
When I run C-c C-c (KnitrLaTeX), emacs runs the following command:
Running `KnitrLaTeX' on `slides.Rnw' with ``Rscript -e "library(knitr); knit('slides.Rnw')" && latexmk -pdf slides.Rnw''
Which is wrong. It should read "... && latexmk -pdf slides.tex"
Thanks in advance.
It appears that you are having trouble with how the second usage of %s is being interpreted at the tail end of your compile command -- i.e., you want the second usage of %s to mean slides.tex instead of slides.Rnw.
Although I am not familiar with knit, I am familiar with creating custom variables for use with AUCTeX. Set forth below are some examples of how to create custom variables and add them to the TeX-expand-list.
Rather than of using %s for a second time (i.e., at the tail end of your compilation command), perhaps consider using %(tex-file-name) instead. This assumes that your *.tex file is open in the buffer with focus when you begin your compilation command -- i.e., the full file name will be inserted into your compilation command.
If you have a file with a different extension that is open in the buffer with focus when you run your compilation command, and if you want the base name to be the same (but with a different extension), then you would do something similar to the example of %(pdf-file-name) -- i.e., remove whatever extension is there and replace it with the new one.
(eval-after-load "tex" '(progn
(add-to-list 'TeX-expand-list '("%(tex-file-name)" (lambda ()
(concat "\"" (buffer-file-name) "\""))))
(add-to-list 'TeX-expand-list '("%(pdf-file-name)" (lambda ()
(concat
"\"" (car (split-string (buffer-file-name) "\\.tex"))
".pdf" "\""))))
(add-to-list 'TeX-expand-list '("%(line-number)" (lambda ()
(format "%d" (line-number-at-pos))))) ))

Perl: How can I get Emacs to add quotes to full path of a Perl script?

Embarassingly simple question. Using CPerl mode in Emacs 23.4.1 on Windows 7 64, when I use C-c c to run the script Emacs doesn't wrap the path in quotes, so any directories with spaces cause Perl to be unable to find the file.
"C:/Perl64/bin\perl.exe -w g:/foo/bar/first second/myscript.pl"
generates this error message:
"Can't open perl script "g:/foo/bar/first": No such file or directory"
Question: how do I make Emacs use quotes when passing the file name to Perl itself?
Edit: for some reason I can't comment (perhaps a browser issue) so I am editing the original post in response to the comment from #legoscia: "C-c c runs the command mode-compile". In the Perl menu it is marked as "Run".
I only have mode-compile.el v2.29 available, but in that version the issue is exactly as you describe, the arguments to the compile command are not escaped properly, and there's no option to enable it.
It's a bit of hack but you should be able to redefine the relevant function with correct escaping for the filename with this in your .emacs file:
(eval-after-load 'mode-compile
'(progn
(defun mc--shell-compile (shell dbgflags &optional errors-regexp-alist)
;; Run SHELL with debug flags DBGFLAGS on current-buffer
(let* ((shcmd (or (mc--which shell)
(error "Compilation abort: command %s not found" shell)))
(shfile (or mc--remote-pathname (buffer-file-name)
(error "Compilation abort: Buffer %s has no filename"
(buffer-name))))
(run-cmd (concat shcmd " " dbgflags " " (shell-quote-argument shfile) " "
(setq mc--shell-args
(read-string (if mode-compile-expert-p
"Argv: "
(format "Arguments to %s %s script: "
shfile shell))
mc--shell-args)))))
;; Modify compilation-error-regexp-alist if needed
(if errors-regexp-alist
(progn
;; Set compilation-error-regexp-alist from compile
(or (listp errors-regexp-alist)
(error "Compilation abort: In mc--shell-compile errors-regexp-alist not a list."))
;; Add new regexp alist to compilation-error-regexp-alist
(mapcar '(lambda(x)
(if (mc--member x compilation-error-regexp-alist) nil
(setq compilation-error-regexp-alist
(append (list x)
compilation-error-regexp-alist))))
errors-regexp-alist)))
;; Run compile with run-cmd
(mc--compile run-cmd)))))
The line I changed was changing
(run-cmd (concat shcmd " " dbgflags " " shfile " "
to
(run-cmd (concat shcmd " " dbgflags " " (shell-quote-argument shfile) " "
A more complete fix would be to also escape the dbgflags (wherever they're set, just escaping the entire variable won't be right) and mc--shell-args when they're set too.

How to define an alternate command for emacs eshell

I'm trying to start using eshell in place of bash within emacs, but I rely heavily on bash functions that I have written over the years. I'd like to configure eshell to invoke bash whenever a "command not found" condition occurs, in case the command in question is implemented as a bash function.
There is a variable tantalizingly named eshell-alternate-command-hook that sounds like it is made to order, but my lack of elisp skill is interfering with my success I think.
This is my best effort:
(add-hook 'eshell-alternate-command-hook 'invoke-bash t t)
(defun invoke-bash (command args)
(throw 'eshell-replace-command
(list "bash -c" command args)))
But when I test it, it doesn't work:
c:/temp $ lsd
Wrong number of arguments: (lambda (command args) (throw (quote eshell-replace-command) (list "bash -c" command args))), 1
c:/temp $
This is what I eventually came up with:
(defun invoke-bash (command)
(progn
(setq invoke-bash-cmd (concat "bash -c \"" command " " (mapconcat 'identity eshell-last-arguments " ") "\""))
(message invoke-bash-cmd)
(throw 'eshell-replace-command
(eshell-parse-command invoke-bash-cmd))))
I'm not eshell guru, but in the place where this hook is used, I see that it receives only one argument - command, that you trying to execute, so your code could look like
(add-hook 'eshell-alternate-command-hook 'invoke-bash)
(defun invoke-bash (command)
(throw 'eshell-replace-command
(list "bash -c" command)))
but it doesn't work, because you need to return elisp function, not name of command (according to documentation). If you want to run bash, then you need to return string with full path to it, but I hadn't found how to pass additional arguments to bash. Maybe you can find more in corresponding section on Emacs Wiki?

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 %