0

I'm working in a custom major mode, and part of the syntax are the square brackets, like [Hello world] and so they can contain nested square brackets as in [Hello [World]], however I see this problem were Emacs will highlight the inner most square bracket first.

This is the current rx expression I have come with using some external help:

(rx (submatch-n 1 "[" (submatch-n 2 (+ (not (any ?[ ?])))) "]"))

It does the job, but I prefer that it match the outer most square bracket first.

  • 2
    It's hard to do using plain regexp:s. If you use code instead, you can find the first and use sexp-forward to find the closing. The next step is to manufacture a match-data, so that you can match the brackets using subexpression font-lock highlights. – Lindydancer May 13 '17 at 18:23
  • 1
    For example: github.com/Lindydancer/objc-font-lock – Lindydancer May 13 '17 at 18:45
  • Let me review that, brb. – shackra May 13 '17 at 21:29
  • @Lindydancer please make your comment an answer – shackra May 14 '17 at 4:48
1

It's hard to match nested parenthesis pairs using plain regexp:s. If you use code instead, you can find the first and use forward-sexp to find the closing. The next step is to manufacture a match-data, so that you can match the brackets using subexpression font-lock highlights.

The following example is from obj-font-lock, a package the highlight Objective-C function calls:

(defun objc-font-lock-match-bracket (lim)
  "Search for an Objective-C method call.

Return non-nil if one is found. The point will be placed after
the start brace. The match data will be filled with the following:

   0 -- The entire method call
   1 -- The start brace
   2 -- The object expression
   3 -- The end brace.

Note that this function is intended to be used by font-lock, and
assumes that comments and string have been fontified."
  (let ((ok nil)
        (beg-of-expr nil)
        (end-of-expr nil))
    ;; Look for "[":s, but skip those that are used for array constructs.
    (while
        (progn
          (setq ok (re-search-forward "\\[" lim t))
          (and ok
               ;; Continue searching, if this bracket isn't suitable.
               (or (objc-font-lock-is-in-comment-or-string)
                   ;; When the `[' doesn't match a `]', skip it.
                   ;; Without this, code after the method call would
                   ;; be fontfied, typically up the the next closing
                   ;; brace.
                   (save-excursion
                     (goto-char (match-beginning 0))
                     (condition-case nil
                         (progn
                           (forward-sexp)
                           (not (eq (char-before) ?\] )))
                       (error nil)))
                   ;; Skip array subscripts.
                   ;;
                   ;; Record the start end end location of the first
                   ;; complex expression, in case this wasn't an array
                   ;; construct.
                   (save-excursion
                     (objc-font-lock-skip-whitespace-etc)
                     (setq beg-of-expr (point))
                     (objc-font-lock-skip-complex-expression)
                     (setq end-of-expr (point))
                     (objc-font-lock-skip-whitespace-etc)
                     (eq (following-char) ?\]))))))
    (if ok
        (let* ((beg (- (point) 1))
               (end (save-excursion
                     (goto-char beg)
                     (forward-sexp)
                     (point))))
          ;; This synthesized match data will be in place for the
          ;; highlights of the keyword as well as when the pre- and
          ;; post-match-forms of the anchored rule are executed.
          (set-match-data (list
                           ;; Match 0: Full range
                           beg end
                           ;; Match 1: [
                           beg (+ beg 1)
                           ;; Match 2: expr
                           beg-of-expr end-of-expr
                           ;; Match 3: ]
                           (- end 1) end))))
    ok))

Your Answer

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

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