user52366
user52366

Reputation: 1137

How do I navigate efficiently through emacs buffer modifying lines

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

Answers (2)

user52366
user52366

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

sds
sds

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

Related Questions