0

I'm trying to highlight variable-type in custom let-like form that looks like:

(mylet ((<variable-type> <variable-name> <variable-value>)
        (...))
  <some-forms>)

To do so I wrote my/highlight-function:

(defun my/highlight-function (bound)
  (when (re-search-forward (rx (: "mylet" (? "*"))) bound 'noerror)
    (ignore-errors
     (let* ((pnt (point))
            (begin (+ (match-end 0) 1))
            (end (scan-sexps pnt 1)))
       (when (and end (not (eql pnt end)))
         (let ((res (map-sorts (buffer-substring-no-properties begin end) begin)))
           (when res
             (store-match-data res)
             t)))))))

(font-lock-add-keywords
 nil
 '((my/highlight-function . font-lock-type-face)))

that 'returns' (saving with a store-match-data) a list of pairs of positions (starting and ending) for each variable type to be highlighted. I am using store-match-data to store the match results since I haven't found a way to use regular expressions directly for my task.

Matching function (actually, out of scope of this question):

(defun find-sorts (text)
  (let ((pos 0)
        (separators '(?\s ?\( ?\)))
        (depth 0)
        (first-name nil)
        (name)
        (names))
    (dolist (sym (coerce text 'list))
      (when (member sym separators)
        (setq first-name nil)
        (when name
          (push pos name)
          (push name names)
          (setq name nil)))
      (when (eql sym ?\() (setq first-name t) (incf depth))
      (when (eql sym ?\)) (setq first-name t) (decf depth))
      (when (and first-name
                 (eql depth 2)
                 (not name)
                 (not (member sym separators)))
        (push pos name))
      (incf pos))
    names))

According to source match-data has following format

 '(full-match-start full-match-end group1-start group1-end ...)

find-sorts wrapper (map-sorts) transforms data to a required format:

(defun map-sorts (text begin)
  (unless (or (equalp text "()")
              (equalp text ""))
    (let ((v (find-sorts text)))
      (append
       (list (+ begin (second (first (last v))))
             (+ begin (first (first v))))
       (reduce
        #'append
        (reverse
         (mapcar (λ (pair)
                   (list (+ begin (second pair))
                         (+ begin (first pair))))
                 v)))))))

At this stage, it turns out that the variable names are stored in separate 'regexp' groups

So the question is:

whether font-lock-add-keywords can highlight all matched groups, not just specified ones or only full matching? Or is there any other way to highlight a similar structural forms other than with one rule?

Even though this (see code below) works, I'm still hoping to find a more elegant solution...

(font-lock-add-keywords
 nil
 '((my/highlight-function
    (1 font-lock-type-face)
    (2 font-lock-type-face)
    ....
    (8 font-lock-type-face)
    (9 font-lock-type-face)))

Сouldn't find anything in the documentation about this. Maybe someone else faced such a problem

Coestaris
  • 1
  • 1
  • You don't show enough of your code to guess what you're doing. `store-match-data` accepts as args the result of the last call to `match-data`, so if that returned a list `(10 20 30 40)` then there should be no problem. But you don't say what the problem is. Just saying that something (which you don't even show *"is not working at all"* doesn't make your problem clear. – Drew Jul 12 '21 at 20:07
  • This: `(list (list 10 20) (list 30 50)))` does not return anything like the list `(10 20 30 50)`. That is, it doesn't return a list such as `match-data` would return. Your question is not very clear. – Drew Jul 12 '21 at 20:08
  • @Drew added the rest of the code. at first I thought the problem was too trivial – Coestaris Jul 13 '21 at 11:08
  • Good. See my previous comment - does `res` give you a flat list of match data, or does it give you a list of pair lists? Oh, and you need to balance your parens (extra `)` in `map-sorts`; missing `)` in `my/highlight-function`). – Drew Jul 13 '21 at 14:22
  • @Drew studied a little the `match-data` format. updated the question, read it, please – Coestaris Jul 13 '21 at 18:12
  • 1
    You can use an *anchored* keyword. This is a nested match where one rule match something, and the inner rule is applied over and over again. (By default, the inner rules is only applied to the current line, but it's possible to apply it to an arbitrary block.) In your case you will only need one face specification. – Lindydancer Jul 15 '21 at 18:47

0 Answers0