Emacs 向 generic-x 模式添加一致的缩进规则
Emacs add consistent indent rule to generic-x mode
我为 Standard ML 写了一个非常简单的 Emacs 模式:
;; sml syntax
(require 'generic-x)
(define-generic-mode
'sml-mode ;; name of the mode
'(("(*" . "*)")) ;; comments delimiter
'("fun" "fn" "let" "val" "datatype" "type" "case" "of" "end" "structure" "struct" "signature" "sig")
'(("=" . 'font-lock-builtin-face)
("|" . 'font-lock-builtin-face)
(">" . 'font-lock-builtin-face)
("<" . 'font-lock-builtin-face)
("-" . 'font-lock-builtin-face)
("+" . 'font-lock-builtin-face)
(";" . 'font-lock-builtin-face)
("," . 'font-lock-builtin-face)
("{" . 'font-lock-builtin-face)
("}" . 'font-lock-builtin-face)
("(" . 'font-lock-builtin-face)
(")" . 'font-lock-builtin-face)
(":" . 'font-lock-builtin-face)
("[" . 'font-lock-builtin-face)
("]" . 'font-lock-builtin-face)) ;; a built-in
'("\.sml$") ;; files that trigger this mode
nil ;; any other functions to call
"SML highlighting mode" ;; doc string
)
但是,它不会缩进一致。我无法准确描述它是如何缩进的,但它在制表符和空格以及空格长度之间的切换不一致。我能想到的最简单的规则是总是在同一列开始一个新行,并且制表符总是带你到下一列,它是 4 的倍数。制表符应该是空格。我如何使用通用模式执行此操作?
关于模式定义的说明,我错误地使用了内置面,因为操作员面没有着色。不过现在确实很难看。
首先:我强烈建议您从 define-derived-mode
而不是 define-generic-mode
开始,因为前者会无缝增长以适应功能齐全的主要模式,而 define-generic-mode
会很快施加不方便解决的限制。
例如您可以将代码重写为:
(defvar sml-mode-syntax-table
(let ((st (make-syntax-table)))
;; Make (*...*) a comment.
(modify-syntax-entry ?\( "()1" st)
(modify-syntax-entry ?\) ")(4" st)
(modify-syntax-entry ?\* ". 23n" st)
st))
(defvar sml-font-lock-keywords
`((,(concat "\_<"
(regexp-opt '("fun" "fn" "let" "val" "datatype" "type" "case" "of" "end" "structure" "struct" "signature" "sig"))
"\_>")
(0 font-lock-keyword-face))
("[][=|><-+;,{}():]" (0 font-lock-builtin-face))))
;;;###autoload
(define-derived-mode sml-mode prog-mode "SML"
"SML major mode."
(set (make-local-variable 'comment-start) "(* ")
(set (make-local-variable 'comment-end) " *)")
(set (make-local-variable 'font-lock-defaults)
'(sml-font-lock-keywords)))
;;;###autoload
(add-to-list 'auto-mode-alist '("\.sml\'" . sml-mode))
W.r.t TAB 和 SPC,"switching between them" 是默认的 Emacs 行为(态度是 TAB 只是我们在适用时使用的优化)。如果你不喜欢它,那么将 (setq-default indent-tabs-mode nil)
放在 你的 ~/.emacs
而不是你的主要模式的定义中,因为这是与 SML 无关的个人选择(不区分 TAB 和 SPC,与 Haskell).
相反
至于你建议的缩进,你可以从添加 (set (make-local-variable 'indent-line-function) #'indent-relative)
开始,这应该确保默认缩进与上一行相同;对于 "TAB should advance by 4 columns" 也许 (set (make-local-variable 'tab-stop-list '(4 8 12 16 20 24 28 32 36 40 44 48 52 56 60 64))
之类的东西可以解决问题(在最近的 Emacsen 中,'(4 8)
就足够了,因为 Emacs 终于学会了 "auto-extend the list".
但我很好奇:为什么不直接使用 GNU ELPA 中现有的 sml-mode
?
我为 Standard ML 写了一个非常简单的 Emacs 模式:
;; sml syntax
(require 'generic-x)
(define-generic-mode
'sml-mode ;; name of the mode
'(("(*" . "*)")) ;; comments delimiter
'("fun" "fn" "let" "val" "datatype" "type" "case" "of" "end" "structure" "struct" "signature" "sig")
'(("=" . 'font-lock-builtin-face)
("|" . 'font-lock-builtin-face)
(">" . 'font-lock-builtin-face)
("<" . 'font-lock-builtin-face)
("-" . 'font-lock-builtin-face)
("+" . 'font-lock-builtin-face)
(";" . 'font-lock-builtin-face)
("," . 'font-lock-builtin-face)
("{" . 'font-lock-builtin-face)
("}" . 'font-lock-builtin-face)
("(" . 'font-lock-builtin-face)
(")" . 'font-lock-builtin-face)
(":" . 'font-lock-builtin-face)
("[" . 'font-lock-builtin-face)
("]" . 'font-lock-builtin-face)) ;; a built-in
'("\.sml$") ;; files that trigger this mode
nil ;; any other functions to call
"SML highlighting mode" ;; doc string
)
但是,它不会缩进一致。我无法准确描述它是如何缩进的,但它在制表符和空格以及空格长度之间的切换不一致。我能想到的最简单的规则是总是在同一列开始一个新行,并且制表符总是带你到下一列,它是 4 的倍数。制表符应该是空格。我如何使用通用模式执行此操作?
关于模式定义的说明,我错误地使用了内置面,因为操作员面没有着色。不过现在确实很难看。
首先:我强烈建议您从 define-derived-mode
而不是 define-generic-mode
开始,因为前者会无缝增长以适应功能齐全的主要模式,而 define-generic-mode
会很快施加不方便解决的限制。
例如您可以将代码重写为:
(defvar sml-mode-syntax-table
(let ((st (make-syntax-table)))
;; Make (*...*) a comment.
(modify-syntax-entry ?\( "()1" st)
(modify-syntax-entry ?\) ")(4" st)
(modify-syntax-entry ?\* ". 23n" st)
st))
(defvar sml-font-lock-keywords
`((,(concat "\_<"
(regexp-opt '("fun" "fn" "let" "val" "datatype" "type" "case" "of" "end" "structure" "struct" "signature" "sig"))
"\_>")
(0 font-lock-keyword-face))
("[][=|><-+;,{}():]" (0 font-lock-builtin-face))))
;;;###autoload
(define-derived-mode sml-mode prog-mode "SML"
"SML major mode."
(set (make-local-variable 'comment-start) "(* ")
(set (make-local-variable 'comment-end) " *)")
(set (make-local-variable 'font-lock-defaults)
'(sml-font-lock-keywords)))
;;;###autoload
(add-to-list 'auto-mode-alist '("\.sml\'" . sml-mode))
W.r.t TAB 和 SPC,"switching between them" 是默认的 Emacs 行为(态度是 TAB 只是我们在适用时使用的优化)。如果你不喜欢它,那么将 (setq-default indent-tabs-mode nil)
放在 你的 ~/.emacs
而不是你的主要模式的定义中,因为这是与 SML 无关的个人选择(不区分 TAB 和 SPC,与 Haskell).
至于你建议的缩进,你可以从添加 (set (make-local-variable 'indent-line-function) #'indent-relative)
开始,这应该确保默认缩进与上一行相同;对于 "TAB should advance by 4 columns" 也许 (set (make-local-variable 'tab-stop-list '(4 8 12 16 20 24 28 32 36 40 44 48 52 56 60 64))
之类的东西可以解决问题(在最近的 Emacsen 中,'(4 8)
就足够了,因为 Emacs 终于学会了 "auto-extend the list".
但我很好奇:为什么不直接使用 GNU ELPA 中现有的 sml-mode
?