reddit / emacs
Emacs Doom: Define a Function to Mark a String in a Buffer
prairie-guy · 2022-07-07 19:38
I am simply trying to write an interactive emacs function that switches butters and marks a string. The function switches buffers and finds the string, but does not mark it. What am I missing? Thanks in advance for any advice.
```emacs
(defun pubmed-find-pmid ()
"From PubMed-Search buffer select `pmid' in PubMed-Entry buffer "
(interactive)
(other-window 1)
(re-search-forward "PMID: ")
(set-mark-command)
(doom/forward-to-last-non-comment-or-eol))
```
Hagge5 · 2022-07-07 19:55
This works for me:
```
(defun pubmed-find-pmid ()
(interactive)
(other-window 1)
(search-forward "PMID: ")
(set-mark-command nil)
(end-of-line))
```
This is of course very hacky, but does what you ask for.
Try calling M-x toggle-debug-on-error. You'll notice that set-mark-command expects one arguments, but you give it 0, so it errors on that line. That's why it never marks it: It crashes before then. Your solution works if you send it nil as an argument.
There are some bat habits in here, of course. (other-window 1) requires a very specific setup for this to work; you probably want to find the appropriate buffer and/or window and use that. You use re-search-forward instead of search-forward. Manipulating the mark like this is probably problematic, especially through set-mark-command, which is a very high-level function mostly intended to be invoked through C-<spc>. But hey, for a hack like this it is probably fine.
prairie-guy · 2022-07-07 20:11
Thanks. Still doesn’t quite work. First time I execute, it ends up going to the end of line (PMID), but it is not marked. Now if I toggle back to the original buffer and execute it again, it is marked. Hmm.
Hagge5 · 2022-07-07 20:19
Works for me with a configless emacs. Not sure if you have any alterations getting in the way.
I can do the following:
* Run emacs -Q to start emacs without any custom configuration (running 28.1)
* Open the scratch buffer
* Paste in this code
* Split the window
* Go to beginning of buffer in both windows
* eval-buffer
* Run pubmed-find-pmid
* ... It marks the ") after the PMID: literal in the other window.
If that works for you it's your config getting in the way somehow.
I don't know enough about mark manipulation via elisp to advice you; never done it. I guess you could try to replace it with (set-mark (point)) for what I guess would be more consistent behavior.
I'm not really following what the documentation is saying, but maybe you wanna finish the function of with an (activate-mark)? Not sure, since I obviously don't need it. Looking at the docs, it seems to imply that this is necessary if transient-mark-mode is disabled, which I guess is something that evil and/or doom might disable? Again, try with emacs -Q.
Are you running with debug on error so you know you're not making it crash, at least?
Edit: An alternative for something as simple as this is creating a macro for it and then converting it to elisp through https://github.com/Silex/elmacro . A macro is intuitive to create, because you see mistakes in real time.
Edit2: It could of course be the mode of your pubmed buffer messing with the mark. Try copying the contents to a text buffer?
mickeyp · 2022-07-07 21:27
For stuff like this, use a keyboard macro.
Record with `F3`; do what you want it to do (switch buffer, search for text, mark text); and stop recording with `F4`. Play it back with `C-x e`.
prairie-guy · 2022-07-07 21:54
Thanks. That’s how I got the basic code for this. I recorded the macro and looked for the commands it used. I want to add to my config.el file as part of a standard workflow. Is there a way to add a macro definition to init.el?
prairie-guy · 2022-07-08 07:02
Thanks for the great suggestions! I appreciate your time and help. Here is what I have found:
- Running `emacs -Q` and running either my original code or your suggested code both work.
- Something in pubmed/doom that is getting in the way
- Per your suggestion, I used `elmacro` and saved the results in my `init.el` file and it works.
- Based upon that code, I thought I may be able to figure out what I need to change, but I still couldn’t get my original code to work.
- As the hack-to-end-all-hacks, I’ve added the elisp equivalent of assembler to my init.el file. It’s ugly, but a solution until I can figure out how to fix this.
For the record, here is what finally worked.
```lisp
(defun last-macro ()
(interactive)
(setq last-command-event 111)
(other-window 1)
(setq last-command-event 19)
(isearch-forward nil 1)
(setq last-command-event 80)
(isearch-printing-char 80 1)
(setq last-command-event 77)
(isearch-printing-char 77 1)
(setq last-command-event 73)
(isearch-printing-char 73 1)
(setq last-command-event 68)
(isearch-printing-char 68 1)
(setq last-command-event 58)
(isearch-printing-char 58 1)
(setq last-command-event 32)
(isearch-printing-char 32 1)
(setq last-command-event 0)
(set-mark-command nil)
(setq last-command-event 5)
(doom/forward-to-last-non-comment-or-eol
(point))
(setq last-command-event 41))
```
mickeyp · 2022-07-08 07:05
Yes. You need to name it with `kmacro-name-last-macro` then go to your `init.el` and type `insert-kbd-macro`. Now you have a callable command.
Hagge5 · 2022-07-08 07:20
Glad it worked, really sorry I couldn't help you further. It's a simple little command, so a shame to run in to do much trouble. I hope it doesn't discourage you from writing more lisp!