user1030520
user1030520

Reputation: 164

repeat macro after error stops execution

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

Answers (3)

phils
phils

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

juanleon
juanleon

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

juanleon
juanleon

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

Related Questions