2

I am trying to figure out how to use window-change-functions refer here for official documentation to be able to run a function to replace certain text within the current buffer at every change of the buffer.

I have the below code, but it does not seem to work:

(defun clean-single-digits (window)
  (with-selected-window window
    (save-excursion
      (goto-char (point-min))
      (while (re-search-forward "I-1" nil t)
        (replace-match "I-01"))))

(add-hook 'window-change-functions #'clean-single-digits)

Much appreciate any help on this, I didn't find any answers online and think this is a useful question. The best example I found was this, which was on a related function.

I was able to get the below working correctly, so the issue is the hook / window-change-function:

(save-excursion
  (goto-char (point-min))
  (while (re-search-forward "I-1" nil t)
    (replace-match "I-01")))
7
  • 1
    C-h v window-change-functions, as well as Elisp manual, node Window Hooks, tell you that each function on that hook must accept a frame, not a window, as its arg. Right away, that indicates that your function needs more work.
    – Drew
    Commented Jul 3, 2021 at 23:05
  • AFAICT, there is no variable called window-change-functions, so doing the add-hook might create such a variable, but nobody is running that hook. There are four window-<mumble>-change-functions hooks, so you would have to decide which one to use. That's in additifon to fixing the function per @Drew's comment.
    – NickD
    Commented Jul 5, 2021 at 17:15
  • What @NickD said. And my comment was misleading/wrong. Depending on the hook you use, the arg passed to the hook functions could be a window or a frame.
    – Drew
    Commented Jul 5, 2021 at 19:44
  • Thanks @NickD and @Drew, this proved helpful. I was able to get it to work by adding a hook to 'after-change-functions, if either of you would like to post an answer with a working solution, I can then accept it. Otherwise I can post something also - I used (add-hook 'after-change-functions 'my-function) and then my-function is a straight forward function that works directly in the current buffer (I use a save-excursion to save the position of the point). Commented Jul 6, 2021 at 5:58
  • My original question is pretty bad now as well, I think I should remove mention to window-change-functions to avoid confusing anyone else. Please feel free to edit the question directly, I'm not a big user of StackExchange so I'm not sure what are the correct conventions to follow Commented Jul 6, 2021 at 6:05

1 Answer 1

2

As discussed in the comments to my question, I was a bit confused when writing the question, but will keep the original text in case similarly inexperienced people approach it from the same way.

To answer the main question "How to dynamically replace certain text, by evaluating a function on change in current buffer", below is an example of how to do it.

In this example, we want to rename all instances of "01" to "1" when our mode is active. The function clean-single-digits achieves this. Note how we use save-excursion to save the current point, i.e. this function replaces all "01" to "1" and returns point to the point it was when the function was called.

The second expression, where we add clean-single-digits to after-change-functions (refer here to the official documentation) ensures this function is called every time Emacs modifies a buffer.

Now you can see why we have (when (eq major-mode 'my-mode)... in our main function - we want our function to only apply in the relevant mode (my-mode in this case) and not for ALL changes in Emacs buffers.

Finally note how our function takes three parameters, which we don't use. Functions that we add to hooks need to have the same number of parameters as per the definition of these hooks - its an important point to read in the documentation of each hook function / variable. You can see references to this detail in the comments to the question.

(defun clean-single-digits (change-beg change-end prev-len)
  (when (eq major-mode 'my-mode)
    (save-excursion
      (goto-char (point-min))
      (while (re-search-forward "01" nil t)
        (replace-match "1")))))

(add-hook 'after-change-functions 'clean-single-digits)

Finally, the window-change-functions referred in the question relate to a different set of hooks that were not appropriate (at least for my approach) to this question. For example window-buffer-change-functions runs on when the actual buffer is changed to something else, not to changes within a buffer.

1
  • +1 - nice, detailed answer!
    – NickD
    Commented Jul 9, 2021 at 13:09

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.