Running emacs keyboard macros in batch mode - emacs

I want to be able to save a keyboard macro in emacs and apply it to a file repeatedly in batch mode. To give a simple example, I made the following file paren-delete.el which is supposed to delete all parentheses and their contents. When I run emacs --batch target.txt --load paren-delete.el, nothing seems to have changed. It appears that only the first kbd function does what it's supposed to, so clearly I don't understand how that command works.
I know that it would be preferable to avoid keyboard macros and write my functions in proper elisp, but I'd prefer a quick-and-dirty solution, and I feel like I'm close.
(kbd "M-x load-library kmacro")
(fset 'delete-paren
(lambda (&optional arg) "Keyboard macro." (interactive "p")
(kmacro-exec-ring-item (quote ("^S(^M^B^#^[^N^W" 0 "%d")) arg)))
(start-kbd-macro nil)
(kbd "M-x delete-paren")
(end-kbd-macro)
(kbd "C-u 0 C-x e")
(save-buffer)

One answer:
Define a function that runs the macro: Write this in an Emacs-Lisp buffer leaving the cursor at the end::
(defun foo ()
M-x insert-kbd-macro RET
Now you have this text, but with the definition of your keyboard macro in place of XXXXX:
(defun foo () (setq last-kbd-macro XXXXX)
Replace setq last-kbd-macro by execute-kbd-macro, and add a final ):
(defun foo () (execute-kbd-macro XXXXX)
Then use C-x C-e after the definition or C-M-x anywhere inside it.
That defines function foo, which does just what your keyboard macro did (in the same context, e.g., same mode, so same key bindings).
Save the definition to your init file. You can use it with Emacs in batch mode. You can also add (interactive) after () to make it a command, so you can use it with M-x.
Another answer:
With Bookmark+, use C-u M-x bmkp-make-function-bookmark to create a bookmark from the last keyboard macro. You are prompted for the bookmark name.
Bookmarks are persistent. To use a bookmark in batch mode, call it as an argument of bookmark-jump, like so: (bookmark-jump THE-BOOKMARK-NAME).

Related

How to set a keybinding to create and jump to the next line in emacs?

I have the following code that attempts to create a new line and then jump to it. The idea is that move-end-of-line will jump to the end of the current line, and ["C-m"] would act as return/enter. Yet executing this command gives the error: "wrong number of arguments". How do I fix this?
(global-set-key (kbd "C-.") 'new-line)
(defun new-line ()
(interactive)
(move-end-of-line)
["C-m"]
)
I think you need to read the Emacs & elisp manuals: these questions are pretty easy to answer. Here's one way to do it.
(defun insert-line-after-line (&optional n)
(interactive "p")
(end-of-line 1) ;end of current line
(open-line n) ;open n new lines
(forward-line 1)) ;go to start of first of them
But seriously: Emacs has very extensive self-documentation, it is easy to find out how to do these things.
An option is to record a macro and use that.
M-x kmacro-start-macro
C-e
C-m
M-x kmacro-end-macro
If you don't care about the macro persisting, just run it:
C-x e
But if you want it to persist you would save it:
M-x name-last-kbd-macro new-line
M-x insert-kbd-macro new-line
and paste the output into your initialisation file (with your shortcut definition):
(global-set-key (kbd "C-.") 'new-line)
(fset 'new-line
[end return])
["C-m"] is like the way you specify a key for doing a key binding, but this is not the same as how you programmatically tell Emacs to insert a character into a document. You could use (insert-char ?\^M) (see ref here), but that would result in a literal ^M character (try it; another way to do the same thing interactively is Ctrl-Q followed by Ctrl-M). (insert "\n") seems to be what you're looking for.
Also, the reason you're getting the message "wrong number of arguments" is because (move-end-of-line) requires an argument when called out of interactive context. (move-end-of-line 1) works.
That said, possibly an easier way to achieve the result you're looking for is with the following setting:
(setq next-line-add-newlines t)
This will allow you to just do C-n at the end of the file and not worry about the distinction between moving and inserting.

Save and execute an Emacs keyboard macro

I have a problem for execute a personal macro in another session in Emacs. I succeeded to create macro and execute then but, after I want to save it for execute them in another time.
For this I write this code in ~/.emacs
(fset 'psTest
(lambda (&optional arg) "Keyboard macro."
(interactive "p")
(kmacro-exec-ring-item (quote ("^X2^X2^X2^X2" 0 "%d")) arg)))
but when I call my macro in another file [ M- x psTest ], Emacs doesn't execute my macro but writes key in my file
^X2^X2^X2^X2
all my commands:
In terminal:
user#PC $ emacs ~/.emacs
In emacs:
C-x (
C-x 2
C-x )
C-x C-k n psTest
M-x insert-kbd-macro [ENTER] psTest [ENTER]
C-x C-c
In terminal:
user#PC $ cat ~/.emacs :
(fset 'psTest
(lambda (&optional arg) "Keyboard macro." (interactive "p") (kmacro-exec-ring-item (quote ("^X2" 0 "%d")) arg)))
user#PC $ emacs ~/test
In emacs:
M- psTest
Now my macro [M- psTest] write ^X2 in my file instead of execute [^X2] which split the screen.
Where is my error?
Thanks
The problem lies in the sequence "^X2" in your macro definition. It contains two characters ^ and X rather than the single character 0x18 in the charset ascii (ASCII (ISO646 IRV)) which is used by emacs to refer to C-x but is displayed the same, though probably in a different color. If you replace the former two-letter-sequence with the latter character and evaluate the definition again, it should work.
You can insert the character with
C-x8RET #x18 RET.
PS: To display information about a specific character at point you can use
M-x desribe-char or what-cursor-position, which is bound to C-x = by default.
I agree with Simon Fromme.
To insert the C-x character, you may omit the #x prefix from his answer and type:
C-x8RET18RET
But you may also simply type C-qC-x in case you don't know the hexadecimal value of the ascii code of this or any other character!
Nevertheless, in your case, I would rather search for the function associated to the C-x 2 sequence. You'll easily find it is split-window-below using either:
C-h k C-x 2 RET
or M-x edit-last-kbd-macro RET
Then you can write some code easier to copy/paste/save like:
(fset 'psTest #'split-window-below)
or
(defun psTest ()
(interactive)
(split-window-below))
This might be a good way to start learning emacs-lisp!

emacs map several keystrokes and command to one key

I'm trying to map c-u m-x indent-pp-sexp to a single key, like F5, so that working with Emacs doesnt erode my fingerprints.
I use (global-set-key (kbd "C-u M-x indent-pp-sexp") "<f5>") but i'm getting the following error:
global-set-key: Key sequence C-u M-x i n d e n t - p p - s e x p starts with non-prefix key C-u
EDIT
With this lambda function (global-set-key (kbd "<f5>") (lambda (interactive) (universal-argument) (indent-pp-sexp t)))
Getting error:
recursive-edit: Wrong type argument: commandp, (lambda (interactive) (universal-argument) (indent-pp-sexp t))
Weird, because univeral-argument takes no parameters, and indent-pp-sexp takes boolean
You have the arguments the wrong way around, and you bind keys to functions, not to other key sequences. Perhaps you are really looking for a named macro; or you can write some actual Lisp and bind that to F5:
(global-set-key (kbd "<f5>")
(function (lambda () (interactive) (indent-pp-sexp t) )) )
The presence of an argument in the call form appears to be sufficient to select the prefix argument functionality.
You're missing the argument list to the lambda. Additionally I think passing t to indent-pp-sexp negates the need to call universal-argument.
(global-set-key (kbd "<f5>") #'(lambda ()
(interactive)
(indent-pp-sexp t)))
I'm a noob like you, but I already happened to figure basic things like making macros. I don't really know what's wrong with your code, but here's walkthrough of how I do things at home. What you need to do first, is press F3. Then type your keystrokes, and when finished, press F4. Congratulations, you have defined an anonymous macro. You can replay it as many times you wish by pressing F4 again. When you have played enough, enter M-x name-last-keybord-macro, and name it eg. foobar. Go to your ~/.emacs.d/macros/ directory (make it if you don't have one) and visit a file that you will name foobar.el. In its buffer, M-x insert-kbd-macro. When asked about name, say foobar. You will see that emacs has entered the contents of your just recorded macro into the file. Save it. Open your .emacs file, and add lines:
(load (expand-file-name "~/.emacs.d/macros/foobar.el"))
(global-set-key (kbd "M-<f5>") 'foobar)
And things start working for me after restart, with M-F5 as the binding for foobar.el macro.

Emacs can't reset Ctrl-d key behaviour

I wanted to change the behaviour of Ctrl-d key. So it will delete a word backward. I created a function:
(defun backward-delete-word (arg)
"Delete characters backward until encountering the beginning of a word.
With argument ARG, do this that many times."
(interactive "p")
(delete-region (point) (progn (backward-word arg) (point))))
Then inserted this into emacs.d:
(global-set-key (kbd "\C-d") 'backward-delete-word)
It works in fundamental-mode, but in php-mode it just removes the next character. When I click
Ctrl-h k Ctrl-d
Emacs gives this:
C-d runs the command c-electric-delete-forward, which is an
interactive compiled Lisp function in `cc-cmds.el'.
It is bound to C-d.
(c-electric-delete-forward ARG)
Somehow, it was reset to another function. How to find out, where it was reset and make it work with my function instead?
I don't have php-mode so I can't say for sure, but the binding is likely overriden in php-mode-map (which, as a major mode map, has higher precedence than the global map).
You can check by using C-h b to list all available key bindings and look for C-d or c-electric-delete-forward in the output buffer to see in which keymap the binding is defined.
Assuming php-mode-map overrides the C-d binding, you can disable it using
(define-key php-mode-map (kbd "C-d") nil)

emacs - set shortcut key only in major mode?

I would like to override C-l and use it to do M-x erase-buffer followed by simulating hitting RET, only when I am in m-shell-mode. C-l should be its default, recenter-top-bottom, otherwise. How do I do so?
Not sure what m-shell-mode is, but if it's a well-defined major mode, then the following should do the trick:
(require 'm-shell-mode)
(define-key m-shell-mode-map (kbd "C-l") 'erase-buffer)
Might I suggest an alternative binding, which has the same visual effect, but keeps the buffer contents around (which can be handy).
(defun shell-clear-command (&optional a)
"\"clear\" the screen"
(interactive "P")
(recenter (or a 0)))
(define-key m-shell-mode-map (kbd "C-l") 'shell-clear-command)
If m-shell-mode is based on comint-mode, which is true of many modes that provide a shell to interact with another process, then you can pass the return keypress to matlab with the function comint-send-input. In that case the following code should do what you want:
(defun clear-and-return ()
"Erases the buffer, and then passes a return to the buffer process.
Assumes the buffer is attached to a comint process."
(interactive)
(erase-buffer)
(comint-send-input))
(defun my-m-shell-mode-hook ()
(local-set-key (kbd "C-l") 'clear-and-return))
(add-hook 'm-shell-mode-hook 'my-m-shell-mode-hook)
The first defun makes a function that does what you want. The second is a hook function that will bind C-l to that function for the buffer that is active when the function is called. The add-hook tells emacs to run the second function whenever you start m-shell-mode. You can add further m-shell-mode customizations inside the body of my-m-shell-mode, and Emacs will run all of them each time you start the mode.
If m-shell-mode is not based on comint-mode, you need to find out what happens when you press return. From a buffer that is running the mode, type C-h k RET to find the function bound to the return key. Use that function instead of comint-send-input in the code above.
You can add to your m-shell-mode hook the following code:
(local-set-key (kbd "C-l") 'erase-buffer)