1

I'm trying to write my first (very simple) major mode for Emacs. My goal is to have multiple comment types, but I can't find a way to implement this. Basically, I want my major mode to make highlighted comments as follows

  • line that comes after #, exactly like in Python
  • line that comes after !, same as above, but with a different color. Also, I want to be able to add a # comment at the end of this line.
  • a code block starting with % and ending in end, again with a different color

So far, I have the following in my .el file:

(defvar my-mode-hook nil)

(defvar my-mode-map
  (let ((map (make-keymap)))
    map)

(defvar my-mode-syntax-table
  (let ((st (make-syntax-table)))
    ;; comment style: "# ..."
    (modify-syntax-entry ?# "<" st)
    (modify-syntax-entry ?\n ">" st)
    (setq comment-start "# ") 
    (setq comment-end "")
    st))

(defvar my-highlights
  '(("!\\|" . font-lock-function-name-face)
    ("!\\([^<]+?\\)\n" . (1 font-lock-function-name-face))))

(define-derived-mode my-mode prog-mode "my-mode"
  (interactive)
  ;; (kill-all-local-variables)
  (use-local-map my-mode-map)
  (set-syntax-table my-mode-syntax-table)
  (setq font-lock-defaults (list nil nil))
  (set (make-local-variable 'font-lock-defaults) '(my-highlights))
  ;; (set (make-local-variable 'indent-line-function) 'my-indent-line)
  (setq major-mode 'my-mode)
  (setq mode-name "MY MODE")

  (run-hooks 'my-mode-hook))

This works somewhat for # and !, but the text highlight for ! comments does not work if I put a # at the end of the line. Also, it only works after I hit enter at the end of the line, not straight after the ! as I write.

An example

2

Here are some tips to get you started:

  • The (setq comment-start/end ..) needs to be within the define-derived-mode, not within that defvar of my-mode-syntax-table (otherwise it just sets the comment style in the buffer that happens to be current when your code loaded, rather than in all the buffers that use your mode).
  • You wan to add (modify-syntax-entry ?! "<" st) since ! also starts a single-line comment.
  • To change the color of comments depending on the char that introduces it, you'll want to set font-lock-syntactic-face-function.
  • You want to add (modify-syntax-entry ?% "< b" st) since % starts a comment, but one that's ended with something else than \n so it needs to use another style (alternatively, you could mark %, \n, and ! as style b and use the "default" style for this one). To mark end as being the matching comment ender, you'll have to use syntax-propertize-function, e.g.

    (setq-local syntax-propertize-local
                (syntax-propertize-rules
                 ("e\\(n\\)\\(d\\)" (1 "w 3b") (2 "w 4b"))))
    

    note that the exact rule to use will depend on whether the end in bending also ends the comment (for example).

  • You don't need (interactive), (use-local-map my-mode-map), (set-syntax-table my-mode-syntax-table), (setq major-mode 'my-mode), (setq mode-name "MY MODE"), nor (run-hooks 'my-mode-hook) since define-derived-mode already does that (tho you might then like to change "my-mode" to "MY MODE").

  • Your code sets font-lock-defaults twice (and not to the same value).

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.