Reputation: 164
My objective is to remove duplicated stanzas in xml files. I am sure I have a duplicated stanza if the first line of the stanza is found multiple times in the file.
I have created a macro that finds the first line of my stanzas through interactive search, then Ctrl-S again to go to the next occurrence. If found, I then mark the section I want to delete and delete it. My macro terminates here.
If my Ctrl-s does not find the next occurrence, my macro stops, which is exacly what I want it to do. However, when I Esc 1000 Ctrl-x e to execute my macro multiple times, when the error is found also the 1000 cycle stops. I am happy for the macro to stop, but I want to execute it again after the error. Is this possible? Or is there already a macro somewhere to remove duplicates stanzas or groups of lines from a file?
My macro:
C-s ;; isearch-forward
<Conduit ;; self-insert-command * 8
SPC ;; self-insert-command
6*C-w ;; kill-region
C-s ;; isearch-forward
C-a ;; beginning-of-line
C-SPC ;; set-mark-command
C-s ;; isearch-forward
< ;; self-insert-command
/ ;; nxml-electric-slash
Conduit> ;; self-insert-command * 8
<right> ;; forward-char
C-w ;; kill-region
Thanks
Joe
Upvotes: 2
Views: 593
Reputation: 73246
Hmm. It would be nice if Emacs provided a convenient interactive way to handle error conditions inside keyboard macros, but I suspect juanleon's answer might be your best bet at present.
A workaround in general is to not use C-s
, but instead use something like M-: (search-forward "foo" nil t) RET
to search for "foo" without triggering an error if it's not there. In this example there would be more to it, though.
For one-off processing, what I tend to do in these kinds of situation is generate a buffer of the results I'm interested in, and then process that with the keyboard macro.
This example is actually a bit tricky, but you could occur
all the lines matching the pattern, pipe through sort | uniq --all-repeated=separate
, and then eliminate the first line of each group. That leaves you with a the exact number of instances you wish to remove for each duplicate, so your keyboard macro could grab a line from that list, find the last instance of it in the original buffer, delete it, and move to the next line in the list.
If this is a common activity, a custom elisp function would seem like the way to go.
Upvotes: 1
Reputation: 9370
If what you want to achieve is to run a macro repeatedly regardless of errors, this would be a way to do it:
(defun repeat-macro-until-abort ()
(interactive)
(while t
(ignore-errors
(kmacro-call-macro 0))))
It will run your last macro until you hit C-g. Please notice that it won't be stopped even by reaching end-of-buffer.
Upvotes: 1
Reputation: 9370
There is a easy way to remove lines that match a regexp: M-x flush-lines
If you know the regexp for the stanza you want to remove, you can type C-M-% <your-regexp> RET RET
and you witll iterate over the occurences chosing what to remove (type ! for removing every of them). C-M-% is the default keybinding for query-replace-regexp
.
Upvotes: 0