Reputation: 1137
I am an elisp (but not programming) beginner and have some questions about the best practice to implement a function. I have written an elisp function that reformats assembler source code according to certain rules; this function currently works for a single line. It basically uses navigation within the line, looking-at and replace-match calls on subexpressions to achieve the goal.
Now I'd like to apply it to a marked region, processing the region line by line. The behaviour will be similar to the indent-region function.
What is the recommended (and efficient) way to implement this? I consider using (line-number-at-pos ...)
applied to (region-beginning)
and (region-end)
to count line numbers and then move from top to bottom, working through the buffer line by line, modifying these.
Also, what would I need to preserve through this operation? I though about (save-match-data ...) and am not sure how to handle mark and point. I guess they will be useless because the text extent changed.
Upvotes: 1
Views: 173
Reputation: 1137
I accept the answer of sds. In the end, I used the code below. The reason was that I wanted entire lines available for reformatting, not just the marked region. So (narrow-to-region)
alone would not have done the job.
I am happy to learn more, and appreciate comments on pros/cons or missing things:
(defun x-mode-reformat-region (beg end)
"..."
(interactive "r")
(save-excursion
(let ((nlines (+ 1 (apply '- (mapcar 'line-number-at-pos `(,end ,beg)))))
bol
...)
(goto-char beg)
(dotimes (i nlines)
(setq bol (line-beginning-position))
(goto-char bol)
;; do reformatting for this line -- uses bol for calculations
(forward-line)))))
Next try -- modified based on comment. I did not find a simpler way to extend the selection to include the entire line... any idea whether the setq
/ narrow-to-region
combination could be simplified further (except using (progn ...)
directly as argument ?
(defun x-mode-reformat-region (beg end)
"..."
(interactive "r")
(save-restriction
(widen)
(save-excursion
(setq beg (progn (goto-char beg) (line-beginning-position))
end (progn (goto-char end) (line-end-position)))
(narrow-to-region beg end)
(goto-char (point-min))
(while (not (eobp))
(insert "*") ;; placeholder for fancy reformatting
(forward-line)))))
Upvotes: -1
Reputation: 60014
Use save-excursion
to save and restore point and mark and save-restriction
to narrow to the region.
The template would be something like this:
(defun my-process-region (beg end)
"Apply `my-process-line` to every line in region."
(interactive "r")
(save-restriction
(widen)
(save-excursion
(narrow-to-region beg end)
(goto-char (point-min))
(while (not (eobp))
(my-process-line)))))
Upvotes: 4