如何使用缩进更改和颜色更改来扩展emacs lisp模式

时间:2010-09-02 00:50:14

标签: emacs lisp elisp

我在lisp中制作DSL(基本上我认为是一种更好的语法),它与lisp相同,除了具有不同的'原语',没有而不是','as'而不是let。因此我需要改变缩进和颜色只在以.goby结尾的文件中(它不应该影响以.lisp结尾的文件)所以我想创建扩展名为.goby的文件,并启用我的新的,次要/主要模式(但是除了从lisp继承的语法之外的所有其他内容)。

然而,无论我做什么,它也会影响.lisp文件!任何人吗?

例如,我尝试为唯一的lisp缩进创建一个局部变量,它会缩进 'hi'乘10个车位。但它影响了所有的.lisp文件

;;in goby.el
(define-derived-mode
  goby-mode lisp-mode "Goby"
  "Major mode"
  (let ((func #'lisp-indent-function))
    (set (make-local-variable 'lisp-indent-function) func)
    (put 'hi 'lisp-indent-function 10)))


(provide 'goby)

;;in .emacs
(setq auto-mode-alist
      (append auto-mode-alist
          '(("\\.gy\\'" . goby-mode))))

1 个答案:

答案 0 :(得分:2)

可能有一种更干净的方式,但一种有效的方法是将'lisp-indent-function重写为'goby-indent-function并使用您自己的偏移表,如下所示:

(define-derived-mode
  goby-mode lisp-mode "Goby"
  "Major mode"
  (set (make-local-variable 'lisp-indent-function) 'goby-indent-function))

;; goby specific offsets here
(put 'hi 'goby-indent-function 10)
(put 'if 'goby-indent-function 4)

(defun goby-indent-function (indent-point state)
  "Same as 'lisp-indent-function but uses 'goby-indent-function symbol

This function is the normal value of the variable `goby-indent-function'.
It is used when indenting a line within a function call, to see if the
called function says anything special about how to indent the line.

INDENT-POINT is the position where the user typed TAB, or equivalent.
Point is located at the point to indent under (for default indentation);
STATE is the `parse-partial-sexp' state for that position.

If the current line is in a call to a Lisp function
which has a non-nil property `goby-indent-function',
that specifies how to do the indentation.  The property value can be
* `defun', meaning indent `defun'-style;
* an integer N, meaning indent the first N arguments specially
  like ordinary function arguments and then indent any further
  arguments like a body;
* a function to call just as this function was called.
  If that function returns nil, that means it doesn't specify
  the indentation.

This function also returns nil meaning don't specify the indentation."
  (let ((normal-indent (current-column)))
    (goto-char (1+ (elt state 1)))
    (parse-partial-sexp (point) calculate-lisp-indent-last-sexp 0 t)
    (if (and (elt state 2)
             (not (looking-at "\\sw\\|\\s_")))
        ;; car of form doesn't seem to be a symbol
        (progn
          (if (not (> (save-excursion (forward-line 1) (point))
                      calculate-lisp-indent-last-sexp))
              (progn (goto-char calculate-lisp-indent-last-sexp)
                     (beginning-of-line)
                     (parse-partial-sexp (point)
                                         calculate-lisp-indent-last-sexp 0 t)))
          ;; Indent under the list or under the first sexp on the same
          ;; line as calculate-lisp-indent-last-sexp.  Note that first
          ;; thing on that line has to be complete sexp since we are
          ;; inside the innermost containing sexp.
          (backward-prefix-chars)
          (current-column))
      (let ((function (buffer-substring (point)
                                        (progn (forward-sexp 1) (point))))
            method)
        (setq method (or (get (intern-soft function) 'goby-indent-function)
                         (get (intern-soft function) 'lisp-indent-hook)))
        (cond ((or (eq method 'defun)
                   (and (null method)
                        (> (length function) 3)
                        (string-match "\\`def" function)))
               (lisp-indent-defform state indent-point))
              ((integerp method)
               (lisp-indent-specform method state
                                     indent-point normal-indent))
              (method
               (funcall method indent-point state)))))))