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

6
  • 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 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 at 20:08
  • @Drew added the rest of the code. at first I thought the problem was too trivial
    – Coestaris
    Jul 13 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 at 14:22
  • 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. Jul 15 at 18:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.