Racket-Mode: Can I evaluate a single form within a given namespace at the REPL? - emacs

I'm working at the Racket REPL via racket-mode in Emacs, writing code in multiple modules.
Is there a way to execute a single form from a module I'm not currently 'in', in the context of its own module?
For instance:
web.rkt
#lang racket
(require "view.rkt")
(define (display-default-view)
(display (default-view)))
view.rkt
#lang racket
(provide default-view)
(define default-text "Hello")
(define (default-view)
(string-append default-text " world"))
If I call racket-run from web.rkt I get a prompt saying web.rkt>. If I then run (display-default-view) I get "Hello world".
If I then visit view.rkt and change the default-text definition to:
(define default-text "Hi")
and re-evaluate the default-text definition, it evaluates fine, and my prompt still says web.rkt>.
When I enter default-text at the REPL I get "Hi". But when I run (display-default-view) I still get "Hello world". I'm presuming this is because all I've done is define a new default-text in web.rkt.
I'd expect to see output change to "Hi world" --- i.e. the behaviour of the view.rkt module to be updated. Just like I'd see if default-text lived in the web.rkt module.
The idea of dynamically re-evaluating single forms at the repl to change program behaviour is terrific, but it seems to not quite work here.
Is there a way to get this behaving as I would expect in racket-mode? Or if not, a mechanism to just enter a module, without running it, so that I can build something myself to do an enter-execute-exit dance?

Updated, simpler answer:
We can evaluate forms in the REPL in the current file's namespace by entering that namespace in the REPL, evaluating these forms, and then re-entering our original namespace. The easiest way to do this seems to be wrapping these forms with functions to enter the current file's namespace (before) and re-entering the original namespace (after) and then sending all of this into the existing Racket-mode code for evaluating forms in the REPL.
We can do this by building a string of our wrapped commands, writing it to a temporary buffer, marking the whole buffer as our region, and then sending it to racket-send-region.
(defun my-racket-current-namespace-wrapped-commands (buffer-file-string commands)
"generate string containing commands wrapped with Racket functions to enter
the current-namespace and then exit it upon finishing"
(concat "(require (only-in racket/enter enter!))"
"(enter! (file "
buffer-file-string
"))"
commands
"(enter! #f)"))
(defun my-racket--send-wrapped-current-namespace (commands)
"sends wrapped form of commands to racket-send-region function via a temporary buffer"
(let ((buffer-file-string (prin1-to-string buffer-file-name)))
(with-temp-buffer
(insert
(my-racket-current-namespace-wrapped-commands buffer-file-string commands))
(mark-whole-buffer)
(racket-send-region (point-min) (point-max)))))
(defun my-racket-send-region-current-namespace (start end)
"send region to REPL in current namespace"
(interactive "r")
(unless (region-active-p)
(user-error "No region"))
(let ((commands (buffer-substring (region-beginning) (region-end))))
(my-racket--send-wrapped-current-namespace commands)))
(defun my-racket-send-last-sexp-current-namespace ()
"send last sexp to REPL in current namespace"
(interactive)
(let ((commands (buffer-substring (my-racket--repl-last-sexp-start)
(point))))
(my-racket--send-wrapped-current-namespace commands)))
(defun my-racket--repl-last-sexp-start ()
"get start point of last-sexp
permanent (and slightly simplified) copy of racket mode's last-sexp-start private function"
(save-excursion
(progn
(backward-sexp)
(if (save-match-data (looking-at "#;"))
(+ (point) 2)
(point)))))
These functions should mostly be version agnostic - they only depend on racket-send-buffer (which seems likely to remain in future versions).
Edit 1: (Note - this does not seem to work as is for newer versions of Racket-mode. This worked as of the April 01, 2018 release, but newer versions seem to have refactored some of the internals this relied on. In almost all cases, the code above is preferable.)
Sorry, I believe that I originally misunderstood the question. It looks like you mean executing the command straight from view.rkt without having to manually change the namespace in the REPL. I didn't see any built-in functionally in racket-mode that does this, but it's not too hard to write an Elisp wrapper around this process. The following imports in enter!, switches to the current buffer's file's namespace, sends the code in the region, and then switches back to the original namespace. The code used is very similar to what racket-mode uses for racket-send-region and racket-send-last-sexp.
(defun my-racket-send-region-current-namespace (start end)
"Send the current region to the Racket REPL as that namespace"
(interactive "r")
(when (and start end)
(racket-repl t)
(racket--repl-forget-errors)
(let ((proc (racket--get-repl-buffer-process)))
(with-racket-repl-buffer
(save-excursion
(goto-char (process-mark proc))
(insert ?\n)
(set-marker (process-mark proc) (point))))
(comint-send-string proc "(require (only-in racket/enter enter!))")
(comint-send-string proc
(concat "(enter! (file "
(prin1-to-string buffer-file-name)
"))"))
(comint-send-string proc "\n"))
(racket--repl-show-and-move-to-end)
(racket--send-region-to-repl start end)
(let ((proc (racket--get-repl-buffer-process)))
(with-racket-repl-buffer
(save-excursion
(goto-char (process-mark proc))
(insert ?\n)
(set-marker (process-mark proc) (point))))
(comint-send-string proc "(enter! #f)")
(comint-send-string proc "\n"))))
(defun my-racket-send-last-sexp-current-namespace ()
(interactive)
(my-racket-send-region-current-namespace
(save-excursion
(backward-sexp)
(if (save-match-data (looking-at "#;"))
(+ (point) 2)
(point)))
(point)))
Note that if you're using this frequently, this function could probably use more error checking (e.g. the import of require/enter will clobber any previous definition of enter!).
I've also kept the original text below about how to manually switch namespaces in the REPL, in case it helps.
You can use the function enter! in the racket/enter module to switch namespaces to modify definitions in the namespace of the other file.
After calling racket-run in web.rkt, you could do the following in the REPL:
(display-default-view) ;; output is "Hello world"
(require racket/enter)
(enter! "view.rkt") ;; change namespace to view.rkt
(define default-text "Hi")
(enter! #f) ;; return to original namespace
(display-default-view) ;; output is "Hi world"
See the Racket documentation for more details on interactive module loading.

Related

ggtags find-definition/reference with IDO interface

I dont like default ggtags interface around ggtags-find-definition/reference/file. I managed to get ggtags-find-file work with IDO, but ggtags-find-definition is a lot harder problem.
Is there some package which can do it? If not, how to make one?
NOTE: I want to be able to browse found definitions/references in fuzzy minibuffer, not whole new buffer (and window).
Normally, I would suggest ido-completing-read-plus (formerly ido-ubiquitous). It makes almost every command that uses completing-read use ido-completing-read instead. However, there is one major case where it doesn't work well: when the completion candidates are generated by a function. This is the case for ggtags-completion-table, which is how ggtags generates its completion candidates.
The solution is to define your own ggtags-completing-read-function that expands the candidates before passing to ido-completing-read. Note: the reason why ido-completing-read (and in turn ido-completing-read-plus) doesn't allow this is because it might use a ton of memory and CPU, and may freeze the UI. You will probably need to tune this to make it acceptable if you have a large number of completion candidates. Also note that most ggtags commands work with the symbol at point; it seems like you generally just give a prefix arg (C-u) to make it prompt for the symbol.
(defun jpk/ggtags-completing-read (&rest args)
(apply #'ido-completing-read
(car args)
(all-completions "" ggtags-completion-table)
(cddr args)))
(setq ggtags-completing-read-function #'jpk/ggtags-completing-read)
Assuming that you ran ggtags-find-definition and it found results and put them in the buffer *ggtags-global*, this function will extract the filenames and line numbers and let you use IDO to pick the one you want.
(defun ido-goto-grep-results (grep-buffer prompt)
(interactive)
(let (candidates result filename dirname line)
(with-current-buffer grep-buffer
(setq dirname default-directory)
(save-excursion
(save-match-data
(goto-char (point-min))
(forward-line 4)
(while (re-search-forward "^\\(.+\\):\\([0-9]+\\):" nil 'noerror)
(push (concat (match-string 1) ":" (match-string 2))
candidates)))))
(setq result (split-string (ido-completing-read prompt candidates nil t) ":"))
(setq filename (car result))
(setq line (string-to-number (cadr result)))
(find-file-other-window (expand-file-name filename dirname))
(goto-char (point-min))
(forward-line (1- line))))
(ido-goto-grep-results "*ggtags-global*" "Jump to definition: ")
This is pretty rough. You probably want to make your own find-definition command that runs ggtags-find-definition and ido-goto-grep-results at once. Somehow you need to only get the actual results and not the "Global found N definitions..." line (better regexp, narrow the ggtags buffer, or some other way).

Emacs AucTeX; How to set C-c C-c default command?

I have set this in my .emacs file:
(add-hook 'TeX-mode-hook
(lambda ()
(setq TeX-command-default "LaTeX"))
(add-hook 'LaTeX-mode-hook
(lambda ()
(setq TeX-command-default "LaTeX"))
I see that C-c C-c is bound to TeX-command-master, which calls TeX-command-query. But since my (TeX-master-file) is "<none>", I expect the default command to be called, but keeps wanting to invoke "View" instead of "LaTeX".
If you check the source for TeX-command-query you'll find that it checks the modification date of the tex (lines 4-9) and bbl (lines 10-19) files involved in your document. Unless those files are more recent than the output file and there is no known next command to be performed (lines 20-22) it will use the "View" command as default (line 23).
This behaviour is of course sensible because normally you don't want to recompile unless there are changes (modified tex files). Apart from "patching" the command [posted below, would not really recommend to use because it will not receive automatic updates ;-) ] there isn't really anything you can do.
If you decide to use the patched command, just put is somewhere in your init file after the original command has been loaded. You could for example wrap it into (replace ;; BODY by code)
(eval-after-load "tex-buf"
'(progn
;; BODY
))
Here comes the patched command:
(defun TeX-command-query (name)
"Query the user for what TeX command to use."
(let* ((default
(cond ((if (string-equal name TeX-region)
(TeX-check-files (concat name "." (TeX-output-extension))
(list name)
TeX-file-extensions)
(TeX-save-document (TeX-master-file)))
TeX-command-default)
((and (memq major-mode '(doctex-mode latex-mode))
;; Want to know if bib file is newer than .bbl
;; We don't care whether the bib files are open in emacs
(TeX-check-files (concat name ".bbl")
(mapcar 'car
(LaTeX-bibliography-list))
(append BibTeX-file-extensions
TeX-Biber-file-extensions)))
;; We should check for bst files here as well.
(if LaTeX-using-Biber TeX-command-Biber TeX-command-BibTeX))
((TeX-process-get-variable name
'TeX-command-next
;; HERE COMES THE PATCH
;; was TeX-command-View
TeX-command-default))
;; END OF PATCH
(TeX-command-Show)))
(completion-ignore-case t)
(answer (or TeX-command-force
(completing-read
(concat "Command: (default " default ") ")
(TeX-mode-specific-command-list major-mode) nil t
nil 'TeX-command-history))))
;; If the answer is "latex" it will not be expanded to "LaTeX"
(setq answer (car-safe (TeX-assoc answer TeX-command-list)))
(if (and answer
(not (string-equal answer "")))
answer
default)))

How to define a wrapper command?

I want to define a modified version of an Emacs command, e.g., browse-url.
The modified version should bind some variables and then defer to the system command, e.g.,
(defun browse-url-incognito (url &rest args)
???
(let ((browse-url-browser-function 'browse-url-generic)
(browse-url-generic-program "google-chrome")
(browse-url-generic-args '("--incognito")))
(apply 'browse-url url args)))
The problem is with the ??? part which should turn the function into an interactive command.
I can, of course, copy over the code from browse-url.el:
(interactive (browse-url-interactive-arg "URL: "))
(unless (called-interactively-p 'interactive)
(setq args (or args (list browse-url-new-window-flag))))
but this feels like cheating (not to mention making my code fragile).
call-interactively seems to foot the bill:
(defun browse-url-incognito ()
"Call `browse-url' displaying in a chrome incognito window."
(interactive)
(let ((browse-url-browser-function 'browse-url-generic)
(browse-url-generic-program "google-chrome")
(browse-url-generic-args '("--incognito")))
(call-interactively 'browse-url)))

AUCTeX: Run Compile Command n-times

I'd like to have a function that asks for a number n and executes the default compile command n-times afterwards. That is to say unlike C-c C-c (i.e. TeX-command-master) I don't want to be asked which command to run, it should select the default compile command based on the AUCTeX settings. Naturally if any error occurs the execution should stop.
I know about TeX-texify, however, this doesn't statisfy my needs because sometimes I just want emacs to run pdflatex five times indepent of what the AUCTeX parser thinks is adequate.
Any help is much appreciated!
Edit: I have looked into this a little further and using code from the above reference I have started writing a function that does this. However, it has one major flaw. Let me first give you the code:
(defcustom TeX-MultiTeX-Command "LaTeX" "Default MultiTeX command" :type 'string :group 'TeX-command)
(defun TeX-MultiTeX (n)
"Run TeX-command n-times"
(interactive "nRun TeX/LaTeX how many times: ")
(while (> n 0)
(TeX-command TeX-MultiTeX-Command 'TeX-master-file)
(setq n (- n 1))))
As you can see, I have implemented a config variable for selecting the correct compilation command. Now let me present the problem:
The compilation of the LaTeX document takes some time, however, my function instantly calls the second (and following) executions of the compile command. Maybe someone can provide help in finding a solution that checks whether compilation has finished successfully prior to executing (TeX-command TeX-MultiTeX-Command 'TeX-master-file), then executes said function or prints some error message if compilation finished with an error.
With the help of the code of the TeX-texify function I have developed a function that does what I want, the code is given below.
I'd like to thank user4815162342; although this solution is not based on his suggestion, I think his solution might be of use for a different problem. Also I'd like to thank TN, the author of TeX-texify, I shamelessly took and adapted his code for my problem. ;)
(defcustom TeX-MultiTeX-Command "LaTeX"
"Default MultiTeX command"
:type 'string :group 'TeX-command)
(defun TeX-MultiTeX-sentinel (&optional proc sentinel)
"Non-interactive! Call the standard-sentinel of the current LaTeX-process.
If there is still something left do do start the next latex-command."
(set-buffer (process-buffer proc))
(funcall TeX-MultiTeX-sentinel proc sentinel)
(let ((case-fold-search nil))
(when (string-match "\\(finished\\|exited\\)" sentinel)
(set-buffer TeX-command-buffer)
(unless (plist-get TeX-error-report-switches (intern (TeX-master-file)))
(TeX-MultiTeX TeX-MultiTeX-num-left)))))
(defun TeX-MultiTeX (n)
"Run TeX-command n-times"
(interactive "nRun TeX/LaTeX how many times: ")
(when (or (called-interactively-p 'any)
(null (boundp 'TeX-MultiTeX-num-left)))
(setq TeX-MultiTeX-num-left n))
(if (>= TeX-MultiTeX-num-left 1)
(progn
(TeX-command TeX-MultiTeX-Command 'TeX-master-file)
(setq TeX-MultiTeX-num-left (- TeX-MultiTeX-num-left 1))
(setq proc (get-buffer-process (current-buffer)))
(setq TeX-MultiTeX-sentinel (process-sentinel proc))
(set-process-sentinel proc 'TeX-MultiTeX-sentinel))))
It seems that you need a synchronous way to run TeX-command. I haven't word with TeX-command, but if it uses the compilation API, it can be made to wait for the compilation to finish, although it's not exactly obvious how to do that. Here is an example that uses compilation-finish-functions to achieve the desired effect:
(require 'cl) ; for lexical-let
(defun compile-and-wait (compilefun)
(interactive)
(lexical-let ((done nil) finish-callback)
(setq finish-callback
;; when the compilation is done, remove the callback from
;; compilation-finish-functions and interrupt the wait
(lambda (buf msg)
(setq compilation-finish-functions
(delq finish-callback compilation-finish-functions))
(setq done t)))
(push finish-callback compilation-finish-functions)
(funcall compilefun)
(while (not done)
(sleep-for .1))))
EDIT
AUC TeX is not using compilation mode to spawn TeX, so the above cannot work. Since it's still useful for other compilation buffers, I'm leaving it in the answer. Another way to implement TeX-MultiTeX is by binding TeX-process-asynchronous to nil, which should ensure that AUC TeX waits for the command to finish.

Emacs/Emacs Lisp: can I insert advice before interactive form? or how to intelligently pre-set the compile-command?

What I'd like to do is intelligently pre-set a buffer-local default value for the string argument to the compile function.
Right now compile.el defaults to using "make" as the command. I can set this by setting compile-command. I can even make that variable buffer-local. That works if I want the same static value, always.
But I'd like to intelligently select the compile-command depending on the contents of the buffer, the name of the buffer, the contents of the containing directory of the file (if any), and the phase of the moon. Basically I want control over the default value, and then allow the interactive user to override that pre-set value.
I was hoping to do this with before-advice. But this isn't working as I expected.
Reading the advice.el file, I see
Suppose a function/macro/subr/special-form has N pieces of before advice, M pieces of around advice and K pieces of after advice. Assuming none of the advices is protected, its advised definition will look like this (body-form indices correspond to the position of the respective advice in that advice class):
([macro] lambda <arglist>
[ [<advised-docstring>] [(interactive ...)] ]
(let (ad-return-value)
{<before-0-body-form>}*
....
{<before-N-1-body-form>}*
{<around-0-body-form>}*
{<around-1-body-form>}*
....
{<around-M-1-body-form>}*
(setq ad-return-value
<apply original definition to <arglist>>)
{<other-around-M-1-body-form>}*
....
{<other-around-1-body-form>}*
{<other-around-0-body-form>}*
{<after-0-body-form>}*
....
{<after-K-1-body-form>}*
ad-return-value))
What this says to me is that when the advised function is interactive, `call-interactively' invokes the interactive form before invoking the before advice, or any advice.
And, when I add advice to compile, the behavior I observe confirms this. The advice gets invoked after the interactive form is processed. The interactive form suggests the string to use for compilation, before my advice gets a chance to guess at what it should be, and to pre-set it.
So...
how can I get my code to run before the interactive form? can advice do this? If not advice, something else? or
how can I dynamically pre-set compile-command for any buffer?
Ideas appreciated.
One option is to set the variable compile-command in a mode hook, something like
(add-hook 'c++-mode-hook 'my-c++-set-compile-command)
(defun my-c++-set-compile-command ()
(setq (make-local-variable 'compile-command) (format "gmake %s" (buffer-file-name))))
I've sometimes added specialized commands to tweak the current compile line (turn on/off debug flags, optimization flags, etc.), and then bind those commands to convenient keystrokes in the mini-buffer.
Regarding adding advice before the interactive form, you need to make advice (either before or around) which has an interactive form that you want. From the advice.el library, an example:
;;(defadvice switch-to-buffer (around confirm-non-existing-buffers activate)
;; "Switch to non-existing buffers only upon confirmation."
;; (interactive "BSwitch to buffer: ")
;; (if (or (get-buffer (ad-get-arg 0))
;; (y-or-n-p (format "`%s' does not exist, create? " (ad-get-arg 0))))
;; ad-do-it))
compile-command doesn't have to be a string. The compile function evals it, so it can be a function that returns a string that's specific to the buffer or that depends on the time of day, etc:
(setq compile-command (lambda () (if (eq phase-of-moon 'waning)
"make -DWANING=1"
"make -DWANING=0")))
Also, though not probably not useful for your specific needs, you can always define compile-command in a file variable section:
/* -*- compile-command: "make -DFOO"; -*- */
or
// Local Variables:
// compile-command: "make -DSOMETHING_SPECIAL"
// End:
compile-command is actually used as an example of a file variable in the manual.
Ahh, you know what I did? I used an oblique strategy.
I have globally set C-xC-e to compile. Instead of using advice, I defined a function that wraps compile, and then bound C-xC-e to that. Within the wrapper, I make the guess for the compile command.
(defun cheeso-invoke-compile-interactively ()
"fn to wrap the `compile' function. This simply
checks to see if `compile-command' has been previously guessed, 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))
And the guess function is like this:
(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
((or (file-expand-wildcards "*.csproj" t)
(file-expand-wildcards "*.vcproj" t)
(file-expand-wildcards "*.vbproj" t)
(file-expand-wildcards "*.shfbproj" t)
(file-expand-wildcards "*.sln" t))
"msbuild ")
;; sometimes, not sure why, the buffer-file-name is
;; not set. Can use it only if set.
(buffer-file-name
(let ((filename (file-name-nondirectory buffer-file-name)))
(cond
;; editing a .wxs (WIX Soluition) file
((string-equal (substring buffer-file-name -4) ".wxs")
(concat "nmake "
;; (substring buffer-file-name 0 -4) ;; includes full path
(file-name-sans-extension filename)
".msi" ))
;; a javascript file - run jslint
((string-equal (substring buffer-file-name -3) ".js")
(concat (getenv "windir")
"\\system32\\cscript.exe c:\\cheeso\\bin\\jslint-for-wsh.js "
filename))
;; something else - do a typical .exe build
(t
(concat "nmake "
(file-name-sans-extension filename)
".exe")))))
(t
"nmake "))))
Here is some code I am using that intelligently selects the compile command courtesy of the University of Wyoming. I currently have it set up for C, C++, and Fortran. You can add more to suit your needs. If I open a programming that has a C++ extension and I execute M-xcompile, my compile command spits out g++ -Wall currentfilename.cpp -o currentfilename -std=c++14. I then just have to hit enter.
;; M-x compile smarter in order to guess language
(require 'compile)
(defvar compile-guess-command-table
'((c-mode . "gcc -Wall -g %s -o %s -lm")
(c++-mode . "g++ -Wall %s -o %s -std=c++14")
(fortran-mode . "gfortran -C %s -o %s")
))
(defun compile-guess-command ()
(let ((command-for-mode (cdr (assq major-mode
compile-guess-command-table))))
(if (and command-for-mode
(stringp buffer-file-name))
(let* ((file-name (file-name-nondirectory buffer-file-name))
(file-name-sans-suffix (if (and (string-match "\\.[^.]*\\'"
file-name)
(> (match-beginning 0) 0))
(substring file-name
0 (match-beginning 0))
nil)))
(if file-name-sans-suffix
(progn
(make-local-variable 'compile-command)
(setq compile-command
(if (stringp command-for-mode)
;; Optimize the common case.
(format command-for-mode
file-name file-name-sans-suffix)
(funcall command-for-mode
file-name file-name-sans-suffix)))
compile-command)
nil))
nil)))
;; Add the appropriate mode hooks.
(add-hook 'c-mode-hook (function compile-guess-command))
(add-hook 'c++-mode-hook (function compile-guess-command))
(add-hook 'fortran-mode-hook (function compile-guess-command))
According to the manual, you can simply override the interactive form of a function with your own by including an interactive form in your advice. I don't think you can modify or wrap the existing interactive form, only override it completely.
http://www.gnu.org/software/emacs/manual/html_node/elisp/Defining-Advice.html