I am writing a mode to color a few common syntax in a symbolic language called FORM. I am a new user of emacs and I took the help of this website to write down the following code. I modified the original code changing the syntax that I want to be colored. But keywords that have special characters (hash # / dot . /underscore _ ), such as "#define", "...", "(dot)sort", "(dot)end", "d_" etc, do not show color.

(setq form-font-lock-keywords
    (let* (
          ;; define several category of keywords
          (x-keywords '("S" "s" "V" "v" "I" "i" "F" "f" "CF" "cf"))
          (x-types '("#define" "..."))
          (x-constants '(".sort" ".end" ".store" ".global" ".clear" ))
          (x-events '("break" "bracket" ))
          (x-functions '("d_" "g_" "g5_" "g6_" "g7_" "gi_"))
          ;; generate regex string for each category of keywords
          (x-keywords-regexp (regexp-opt x-keywords 'words))
          (x-types-regexp (regexp-opt x-types 'words))
          (x-constants-regexp (regexp-opt x-constants 'words))
          (x-events-regexp (regexp-opt x-events 'words))
          (x-functions-regexp (regexp-opt x-functions 'words)))

        (,x-types-regexp . font-lock-type-face)
        (,x-constants-regexp . font-lock-constant-face)
        (,x-events-regexp . font-lock-builtin-face)
        (,x-functions-regexp . font-lock-function-name-face)
        (,x-keywords-regexp . font-lock-keyword-face)
        ;; note: order above matters, because once colored, that part won't change.
        ;; in general, put longer words first

(define-generic-mode  form-mode nil  "form mode"
   "Major mode for editing FORM symbolic tool."

    ;; code for syntax highlighting
    (setq font-lock-defaults '((form-font-lock-keywords))))

(provide 'form-mode)

To my understanding, what I did was:

  1. I have defined categories of the keywords --> x-name of the category

  2. Generated regular expression - regex (I am not sure of its function in this context) for each category

  3. assigned regex to a font that has unique color

  4. set nil as parent mode

At first I thought that my parent mode was not accurate to show color for #/./_ symbols, but now I think that's not the main issue. I think the problem comes from 1-3 options. Please provide your valuable suggestion on this problem. Many thanks!

1 Answer 1


I think that is because (regexp-opt foo 'words) assumes that your keywords are, well, words. Try to rewrite those expressions (and only those, leave the alphabetic ones alone) like this:

(defun gmunu--concat-regexp (stuff)
  (if (null stuff) ""
    (let ((result (regexp-quote (car stuff)))
          (remaining (cdr stuff)))
       (while remaining
          (setq result (concat result "\\|" (regexp-quote (car remaining))))
          (setq remaining (cdr remaining)))

and then change (regexp-opt foo 'words) to (gmunu--concat-regexp foo)

Untested, but I'm confident this is the gist of the problem.

  • I think I misinterpreted what I should replace by "stuff". Can you please tell me what exactly should I change? lang-lisp (defun gmunu--concat-regexp (stuff) (unless stuff "") (let ((result (regexp-quote (car stuff))) (remaining (cdr stuff))) (while remaining (setq result (concat result "\\|.sort\\|.end\\|.store\\|" (regexp-quote (car remaining)))) (setq remaining (cdr remaining))) result)) (setq form-font-lock-keywords ( *only change in generating regex string* (x-functions-regexp (gmunu--concat-regexp x-functions))) May 21, 2020 at 6:20
  • stuff stands for the list of non-alphabetic patterns, so what I mean is for example ... (x-types-regexp (gmunu--concat-regexp '("..." "#define"))) ... and so on. There is a loose end in that #define may match even if followed by an alphabetic character which is probably not what you want. Think about solving that on your own for a bit before coming back here. (I mean that as a friend, and I don't mean I'll refuse to help more if you really need it.)
    – q.undertow
    May 22, 2020 at 0:17

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.