I've noticed a trend in my code of repeating the same (with-current-buffer .... over and over again so I decided to define a macro based off that macro definition of with-current-buffer - this is what I have so far:
(defmacro with-assembla-buffer(asm-buffer-name heading-str &rest body)
"Create buffer with name of ASM-BUFFER-NAME, or uses it if exists,
preps it with readonly/erase/heading - executes `body' - then puts
readonly back on, goes to beginning of buffer, and switches to it."
(with-current-buffer (get-buffer-create asm-buffer-name)
(assembla-mode)
(toggle-read-only -1)
(erase-buffer)
(insert (format "-- %s --------------------" heading-str))
(newline)
`(progn ,#body)
(toggle-read-only 1)
(goto-char (point-min))
(switch-to-buffer (current-buffer))))
The body of this is never being executed, however when it's switched to defun instead of defmacro is does work perfectly. So aside from why is body never executed, my other question is - does this make more sense as a macro than a defun?
Remember, a macro generates code. Your macro looks like it does not. Check out a macro expansion of an example call. The first step of debugging a macro is to check the macro expansion of some code.
....
(with-current-buffer (get-buffer-create asm-buffer-name)
Above: why is this as code in the macro and not as source code? This code will be executed when the macro is expanded, it won't appear in the generated code. You probably want to backquote it.
(assembla-mode)
(toggle-read-only -1)
(erase-buffer)
(insert (format "-- %s --------------------" heading-str))
(newline)
`(progn ,#body)
Above: this won't do what you want. You need to backquote ALL the code you want to generate - not just this form.
Related
I'm writing a comint mode for a legacy command-line tool.
I'd like to add basic auto-completion to it.
Suppose I have the following list of keywords used by the tool:
(defconst my-keywords '("export" "extract" "display"))
How would I add auto-completion to my mode, based on this list?
What I found so far:
I know there are examples of this in shell.el or in comint.el, but I did not manage to understand the code well enough to answer to this basic question. I did understand though that I could build a regexp list out of my-keywords, like this:
(regexp-opt my-keywords)
;; output:
"\\(?:display\\|ex\\(?:\\(?:por\\|trac\\)t\\)\\)"
Other than that, I gathered that I could use pcomplete, or company, or both – I'm fine with any solution actually, but how do I do it?
Comint also calls customizable comint-dynamic-complete-functions from its comint-completion-at-point function. Derived modes will often add functions to this hook (see shell-dynamic-complete-functions), eg.
(defconst my-keywords '("export" "extract" "display"))
(defun my-comint-dynamic-completion-function ()
(when-let* ((bds (bounds-of-thing-at-point 'symbol))
(beg (car bds))
(end (cdr bds)))
(when (> end beg)
(list beg end my-keywords :annotation-function (lambda (_) "my-keywords")))))
(define-derived-mode my-comint-mode comint-mode "my mode"
(add-hook 'comint-dynamic-complete-functions
#'my-comint-dynamic-completion-function nil 'local)
(make-local-variable 'company-backends)
(cl-pushnew 'company-capf company-backends))
By adding company-capf to your company-backends you will additionally get company support from your completion at point function (see elisp-completion-at-point for example of additional company-specific symbols for showing help/location/etc. of completion candidates).
Thanks to ergoemacs I found a first solution :
Define a completion function which returns a list of the form (start end my-keywords . nil), with start and end delimiting the entity to complete at point. I added a tweak to take into account the program prompt, for the first keyword.
Add this function to completion-at-point-functions, in the definition of the mode;
Add a tab shortcut to completion-at-point, in the mode-map.
(defconst my-keywords '("export" "extract" "display"))
;; 1 - custom completion function
(defun my-completion-at-point ()
"This is the function to be used for the hook `completion-at-point-functions'."
(interactive)
(let* (
(bds (bounds-of-thing-at-point 'symbol))
(start (max (car bds) (comint-line-beginning-position)))
(end (cdr bds)))
(list start end xyz-keywords . nil )))
;; 2 - adding it to my-completion-at-point
(define-derived-mode my-comint-mode comint-mode "My comint mode"
;; your code....
(add-hook 'completion-at-point-functions 'my-completion-at-point nil 'local))
;; 3 - add a tab shortcut in the map of the mode
(defvar my-mode-map
(let ((map (nconc (make-sparse-keymap) comint-mode-map)))
;; your code...
(define-key map "\t" 'completion-at-point)
map))
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.
How can I get create an autoloaded function from a macro function factory? For example, say I have a macro to create alignment functions as follows, but I want to be able to specify an option so the expanded macro has an autoload cookie.
(defmacro align-by (name doc regex)
"Alignment function factory."
(declare (indent 1))
(let ((fn (intern name)))
`(defun ,fn (start end)
,doc
(interactive "r")
(align-regexp start end ,regex))))
(align-by "align-backslash"
"Align backslashes at end of line in region."
"\\(\\s-*\\)\\\\$")
I know I can write this, but can I avoid needing to write this for every function?
;;;###autoload (autoload 'align-backslash "this-file")
It's not clear where the macro would pick up the name of the file to be autoloaded - you do not pass a file name to the macro, currently.
Assuming that the file name comes from a file that is being visited when the macro is expanded, this will do it:
(defmacro align-by (name doc regex)
"Alignment function factory."
(declare (indent 1))
(let ((fn (intern name)))
`(progn
,(and (buffer-file-name)
`(autoload ',name ,(buffer-file-name)))
(defun ,fn (start end)
,doc
(interactive "r")
(align-regexp start end ,regex)))))
Testing:
(macroexpand '(align-by "align-backslash"
"Align backslashes at end of line in region."
"\\(\\s-*\\)\\\\$"))
C-u C-x C-e shows that that gives this when the current buffer is not visiting a file:
(progn
(autoload '"align-backslash" nil)
(defun align-backslash
(start end)
"Align backslashes at end of line in region."
(interactive "r")
(align-regexp start end "\\(\\s-*\\)\\\\$")))
And it gives this when the buffer is visiting file foo.el, where ".../foo.el" is really the absolute file name for foo.el:
(progn
(autoload '"align-backslash" ".../foo.el")
(defun align-backslash
(start end)
"Align backslashes at end of line in region."
(interactive "r")
(align-regexp start end "\\(\\s-*\\)\\\\$")))
The code that picks up the ;;;###autoload cookies does expand the macros before looking at the code, so you should be able to just place a ;;;###autoload cookie right before a (align-by ...) expression and get the right autoload placed in the <foo>-autoloads.el file.
The problem, tho is that your macro is probably not going to be defined at the time the autoloads are created, so the macro expansion will not actually happen. Maybe a M-x report-emacs-bug is in order.
As emacs manual mentioned
If you write a function definition with an unusual macro that is not one of the known and recognized function definition methods, use of an ordinary magic autoload comment would copy the whole definition into loaddefs.el. That is not desirable. You can put the desired autoload call into loaddefs.el instead by writing this:
;;;###autoload (autoload 'foo "myfile")
(mydefunmacro foo
...)
Your align-by is like mydefunmacro in the manual example. It is not known function definition method and it is not supported by autoload mechanism.
So there are three alternatives:
Extend the list of supported types (defun, defmacro, cl-defun, defclass,...) by your special macros. Then you can use simple ;;;###autoload "decorator".
Invent your own mechanism of "myfile" parsing (without executing) and "loaddefs" populating by necessary autoload definitions.
Use more complicated construction (with (autoload 'align-backslash "myfile")) as function defintion method.
If you rewrite align-by like this (without intern):
(defmacro align-by-defun (name doc regex)
"Alignment function factory."
(declare (indent 1))
`(defun ,name (start end)
,doc
(interactive "r")
(align-regexp start end ,regex)))
;;;###autoload (autoload 'align-backslash "myfile")
(align-by-defun align-backslash
"Align backslashes at end of line in region."
"\\(\\s-*\\)\\\\$")
you can see that align-by is just a function definition method (like cl-defun).
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.
does anyone know of some good elisp macros for cleaning up LaTeX code?
I do a lot of LaTeX editing of other peoples sources and I'd like to extend my set of clean up tools since not everyone organize their code in the manner I like it ;-)
One in particular would be interesting, to run function X on a buffer and get all LaTeX environments (\begin{...} and \end{...} pairs) to sit on lines of their own, this helps readability of the code.
I could try this myself, but would like to hear suggestions as to a best practice for programming such a function, e.g. it should of course not introduce blank lines of its own.
suggestions?
Edit: For the archives, here are my current version based on the answer given (assumes the use of auctex). It more or less suits my needs at the moment. I added the y-or-n test just to be able to detect corner cases that I had not thought of.
(defun enviro-split ()
"Find begin and end macros, and put them on their own line."
(interactive)
(save-excursion
(beginning-of-buffer)
;; loop over document looking for begin and end macros
(while (re-search-forward "\\\\\\(begin\\|end\\)" nil t)
(catch 'continue
; if the line is a pure comment, then goto next
(if (TeX-in-commented-line)
(throw 'continue nil)
)
;; when you find one, back up to the beginning of the macro
(search-backward "\\")
;; If it's not at the beginning of the line, add a newline
(when (not (looking-back "^[ \t]*"))
(if (y-or-n-p "newline?")
(insert "\n")
)
)
;; move over the arguments, one or two pairs of matching braces
(search-forward "{") ; start of the argument
(forward-char -1)
(forward-sexp) ; move over the argument
(if (looking-at "[ \t]*{") ; is there a second argument?
(forward-sexp)
) ; move over it if so
(if (looking-at "[ \t]*\\[") ; is there a second argument?
(forward-sexp)
) ; move over it if so
(when (looking-at (concat "[ \t]*" (regexp-quote TeX-esc) "label"))
(goto-char (match-end 0))
(forward-sexp)
)
(if (looking-at (concat "[ \t]*%" ))
(throw 'continue nil)
)
;; If there is anything other than whitespace following the macro,
;; insert a newline
(if (not (looking-at "\\s *$"))
;;(insert "\n")
(if (y-or-n-p "newline (a)?")
(insert "\n")
)
)
) ; end catch 'continue
)
(LaTeX-fill-buffer 'left)
)
)
You could probably work up a single regexp and do a regexp replace for this. However, I find the logic of these manipulations becomes pretty hairy, particularly when you want to account for various edge-cases. In your example, you need to deal with some environments taking one argument, while others take two. I think it is easier to combine a series of simple regexps with basic text editing commands for this:
(defun enviro-split ()
"Find begin and end macros, and put them on their own line."
(interactive)
(save-excursion
(beginning-of-buffer)
;; loop over document looking for begin and end macros
(while (re-search-forward "\\\\\\(begin\\|end\\)" nil t)
;; when you find one, back up to the beginning of the macro
(search-backward "\\")
;; If it's not at the beginning of the line, add a newline
(when (not (looking-at "^"))
(insert "\n"))
;; move over the arguments, one or two pairs of matching braces
(search-forward "{") ; start of the argument
(forward-char -1)
(forward-sexp) ; move over the argument
(if (looking-at "\\s *{") ; is there a second argument?
(forward-sexp)) ; move over it if so
;; If there is anything other than whitespace following the macro,
;; insert a newline
(if (not (looking-at "\\s *$"))
(insert "\n")))))
This approach has the advantage of using Emacs' built-in functions for moving over sexps, which is much easier than coming up with your own regexp that can handle multiple, potentially nested, expressions inside braces.