0

I want to remove timestamps from a server log:

2023-11-22T11:36:28: # error! 
2023-11-22T16:11:36: ...
2023-11-22T16:11:36: # new error!

Manually, I select the region at the buffer start, go to the end, move to the first character after the timestamp, and execute C-x r d. So I wrote checked the documentation for delete-rectangle:

(delete-rectangle START END &optional FILL)

Delete (don’t save) text in the region-rectangle. The same range of columns is deleted in each line starting with the line where the region begins and ending with the line where the region ends.

and wrote this program:

(defun my-clean ()
  (interactive)
  (save-excursion
    (push-mark (point-min))
    (activate-mark)
    (goto-char (point-max))
    (message (format "Region: %d - %d"  (mark) (point)))
    (delete-rectangle 0 21)))

But this only deletes the timestamp in the first line, not the whole region. Why does the function not work as when called interactively?

2
  • 1
    The region you specify in the delete-rectangle call is (0 21) which covers the timestamp of the first line. Try M-g c 0 and M-g c 21 to interactively go to the two ends of the region. The interactive call calculates the two ends of the region implicitly but correctly.
    – NickD
    Nov 23, 2023 at 13:57
  • 1
    emacs.stackexchange.com/tags/elisp/info
    – Drew
    Nov 23, 2023 at 17:13

1 Answer 1

2

You don't need to set the mark in the function, but you do need to calculate the two ends of the region correctly. (point-min) is the correct beginning [1], but the end of the region is not 21, and it is not (point-max): you'll have to search somehow and find that position.

Let's assume that you have a function that returns the position after the last timestamp in the file (without any side effects, e.g. point is not affected by the function). Then all you need to do is

(delete-rectangle (point-min) (point-after-last-timestamp))

and my-clean is then:

(defun my-clean ()
   (interactive)
   (delete-rectangle (point-min) (point-after-last-timestamp)))

The only problem then is to calculate the position after the last timestamp. One possibility is to move to the beginning of the last line, then move forward 20 characters, since the timestamp is of fixed width:

(defun point-after-last-timestamp ()
   (save-excursion
       (goto-char (point-max))
       (forward-line -1)
       (forward-char 20)
       (point)))

We move point to the right place [2] (inside a save-excursion so that we avoid any side effect) and return the value of point when we get there.


Footnotes:

[1] Assuming that there is no narrowing. The value that point-min returns is 1 BTW, not 0, but delete-rectangle does not mind that.

[2] There is an implicit assumption here that the buffer ends with a newline: if not, the logic is somewhat different, but I left that complication for the interested reader to resolve...

1
  • Yes, of course! Thank you for the clarification and for teaching me the logic of E-lisp.
    – emonigma
    Nov 23, 2023 at 14:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.