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!