4

I have one big org file. Sometimes I only want to search for a regular expression through the visible text, not the text that is folded; otherwise my search will take much longer.

How can I search for a regex match in only visible portion of a buffer?

I thought if a macro like with-visible-text existed it would be ideal. So something like (with-visible-text (re-search-forward "some regexp" nil t)) would search through only visible text.

I have tried to get hints on how to do this with forward-visible-line. And I've seen I things like look promising like (next-single-property-change (point) 'invisible) which gives the the position of the next point that's not invisible. So I'm thinking maybe the solution to this is using re-search-forward with a boundaries which contain only visible regions.

2 Answers 2

4

After doing some research I realized that first I worded my question imprecisely because I was not aware of the term for describing text that is invisible through folding. The term is overlay.

Essentially I wanted re-search-forward (or other search functions) to skip overlays.

To achieve this I wrote this macro using the ov library for convenience (although this can be done just as well with regular emacs functions). The macro checks to see that calling the search function will result in landing in an invisible overlay, if it does it goes to the end of the overlay and tries again until it's no longer in an invisible overlay. Note ov-end is noninclusive (you cant be in and overlay after ov-end).

I have tried this with (+with-ignore-invisible-overlays (re-search-forward "\\w\\b t 1)) on a 5000+ line org file with folded headings until I got to the end. And looked at how many times it searched and what points were produced. It only produced points in the non-folded regions.

Note: this kind of thing can be really useful for making custom functions in evil-easymotion where it doesn't make sense to count visible text.

(defmacro +with-ignore-invisible-overlays (&rest form)
  "Form should be a callable that returns a point based on the current point."
  (let ((search-fun (car form))
        (args (rest form))
        (overlay nil)
        (point nil))
   `(progn
       (setq point ,@form)
       (setq overlay (ov-at (point))) 
       (while (and overlay (member 'invisible (ov-prop overlay)))
         (goto-char (ov-end overlay))
         (setq point ,@form)
         (setq overlay (ov-at (point))))
       point)))
2

Customizing variable search-invisible accordingly should do the trick.

3
  • 1
    When I tried setting search-invisible to nil. re-search-forward was still looking through invisible text. To test this I tried (re-search-forward "\\w\\b" nil t) on a large org file with headings folded. Based on the documentation of search-invisible I think it works only with search/query-replace. Mar 8, 2018 at 19:05
  • The same appears to be true of re-search-forward
    – Att Righ
    Dec 5, 2022 at 17:18
  • Isearch and query-replace don't match hidden text here. Same with re-search-forward. Are you sure, customization to nil was active? Dec 6, 2022 at 19:54

Your Answer

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

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