DerivedMode

Instead of writing a new MajorMode from scratch, you should derive your new mode from an existing mode. Deriving a new mode from fundamental mode (which does basically nothing) is better than writing a new mode from scratch. (Unless you know what you are doing, of course.)

It may be useful to refer to the GNU documentation on derived modes.

Here’s an example of how to translate a very simple GenericMode code sample into a DerivedMode code sample. This would be the way to go if you think that GenericMode is too limiting for your needs.

Old GenericMode code:

 (define-generic-mode `kk-mode
   ()
   ()
   '(("\\(--.*\\)" 1 'font-lock-comment-face))
   ()
   (list (lambda () (set (make-local-variable 'comment-start) "--")))
   "Major mode to edit KK files.")

New DerivedMode code:

  (defvar mydsl-constants
    '("reservedword1"
      "reservedword2"))
  
  (defvar mydsl-keywords
    '("other-keyword" "another-keyword"))
  
  ;; I'd probably put in a default that you want, as opposed to nil
  (defvar mydsl-tab-width nil "Width of a tab for MYDSL mode")
  
  ;; Two small edits.
  ;; First is to put an extra set of parens () around the list
  ;; which is the format that font-lock-defaults wants
  ;; Second, you used ' (quote) at the outermost level where you wanted ` (backquote)
  ;; you were very close
  (defvar mydsl-font-lock-defaults
    `((
       ;; stuff between double quotes
       ("\"\\.\\*\\?" . font-lock-string-face)
       ;; ; : , ; { } =>  @ $ = are all special elements
       (":\\|,\\|;\\|{\\|}\\|=>\\|@\\|$\\|=" . font-lock-keyword-face)
       ( ,(regexp-opt mydsl-keywords 'words) . font-lock-builtin-face)
       ( ,(regexp-opt mydsl-constants 'words) . font-lock-constant-face)
       )))
  
  (define-derived-mode mydsl-mode fundamental-mode "MYDSL script"
    "MYDSL mode is a major mode for editing MYDSL files"
    ;; you again used quote when you had '((mydsl-hilite))
    ;; I just updated the variable to have the proper nesting (as noted above)
    ;; and use the value directly here
    (setq font-lock-defaults mydsl-font-lock-defaults)
  
    ;; when there's an override, use it
    ;; otherwise it gets the default value
    (when mydsl-tab-width
      (setq tab-width mydsl-tab-width))
  
    ;; for comments
    ;; overriding these vars gets you what (I think) you want
    ;; they're made buffer local when you set them
    (setq comment-start "#")
    (setq comment-end "")
  
    (modify-syntax-entry ?# "< b" mydsl-mode-syntax-table)
    (modify-syntax-entry ?\n "> b" mydsl-mode-syntax-table)
  
    ;; Note that there's no need to manually call `mydsl-mode-hook'; `define-derived-mode'
    ;; will define `mydsl-mode' to call it properly right before it exits
    )
  
  (provide 'mydsl-mode)

If you are are deriving your new mode from something other than fundamental-mode, you may want to add to that mode’s set of existing keywords.

    (defface c3-face-1 
      '((t (:foreground "#FF0000")))
      "red")
    
    ;; c3-mode 
    (define-derived-mode c3-mode sgml-mode 
     "c3-mode" 
     "A variant of SGML mode. Numbers appear in red."
    
     (font-lock-add-keywords nil '(("[0-9]" . 'c3-face-1)))
    )

By default, syntax highlighting will font lock quoted strings. If you don’t want that to happen, add a ‘t as the last element in the font lock list, as shown in this link.


CategoryCode