Effortless Major Mode Development

28 April 2016

It’s now easier than ever to write major modes in Emacs. If you haven’t written a major mode in a while, or you’re just starting out, here are my three top tips:

Use regexp-opt

As of Emacs 24, regexp-opt takes a 'symbols option. You should write your font-lock keywords like this:

(defvar js-mode-font-lock-keywords
  `((,(regexp-opt
       '("var" "for" "function" "if" "else")
       'symbols)
     . font-lock-keyword-face)

This has two advantages. By whitelisting keywords, users can quickly spot mistakes when editing:


This also prevents a classic bug where Emacs highlights substrings that happen to be keywords:


(Don’t) use company

Company is excellent, and I highly recommend it. However, not all Emacsers use company. You don’t need to force company on your users.

Instead, you can use completion-at-point-functions . Your completion functionality will work in stock Emacs, and company users will benefit too through company-capf .

Ah, but what about all the extra annotations you can supply to company? We can have our cake and eat it too:

(defun racer-complete-at-point ()
  "Complete the symbol at point."
  (unless (nth 3 (syntax-ppss)) ;; not in string
    (let* ((bounds (bounds-of-thing-at-point 'symbol))
           (beg (or (car bounds) (point)))
           (end (or (cdr bounds) (point))))
      (list beg end
            (completion-table-dynamic #'racer-complete)
            :annotation-function #'racer-complete--annotation
            :company-prefix-length (racer-complete--prefix-p beg end)
            :company-docsig #'racer-complete--docsig
            :company-location #'racer-complete--location))))

Test with assess

Historically, it’s been rather awkward to test major modes. Many authors didn’t bother.

That’s all changed with the release of assess . Assess provides great assertions with readable error messages.

For example, here’s a simple indentation test from cask-mode :

(ert-deftest cask-mode-indent-inside-development ()
  "Ensure we correctly indent inside (development ...) blocks."
  (should (assess-indentation=
           'cask-mode
           ;; before:
           "
(development
(depends-on "foo"))"
           ;; after:
           "
(development
 (depends-on "foo"))")))

Highlighting is particularly helped by assess:

(ert-deftest cask-mode-highlight-sources ()
  "Ensure we highlight known values for source."
  (should (assess-face-at=
           "(source melpa)"
           'cask-mode
           "melpa"
           'cask-mode-source-face)))

If this test fails, we get a helpful message describing which faces were actually used:

#("Face does not match expected value
   Expected: cask-mode-source-face
   Actual: font-lock-keyword-face
   Location: 9
   Line Context: (source melpa)
   bol Position: 1"

These tips are all new things I’ve learnt writing a new major mode for Cask files . If you’re just getting started with Emacs development, check out adding a new language to Emacs . Finally, if I’ve missed your favourite tip, leave a comment on the /r/emacs discussion !

稿源:Wilfred Hughes Blog (源链) | 关于 | 阅读提示

本站遵循[CC BY-NC-SA 4.0]。如您有版权、意见投诉等问题,请通过eMail联系我们处理。
酷辣虫 » 后端存储 » Effortless Major Mode Development

喜欢 (0)or分享给?

专业 x 专注 x 聚合 x 分享 CC BY-NC-SA 4.0

使用声明 | 英豪名录