Emacs добавляет согласованное правило отступа в режим generic-x

Я написал очень простой режим Emacs для Standard ML:

;; 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. Вкладки должны быть пробелами. Как я могу сделать это, используя общий режим?

Как примечание к определению режима, я неправильно использую встроенное лицо, потому что лицо оператора не имеет раскраски. Теперь это выглядит ужасно.

1 ответ

Решение

Перво-наперво: я настоятельно рекомендую вам начать с 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))

Что касается TAB и SPC, "переключение между ними" является поведением Emacs по умолчанию (отношение к этому заключается в том, что TAB - это просто оптимизация, которую мы используем, когда это применимо). Если тебе не нравится, то ставь (setq-default indent-tabs-mode nil) в вашем ~/.emacs и не в определении вашего основного режима, так как это личный выбор, не связанный с SML (который не различает TAB и SPC, в отличие, скажем, от Haskell).

Что касается отступа, который вы предлагаете, вы можете начать с добавления (set (make-local-variable 'indent-line-function) #'indent-relative) который должен убедиться, что отступ по умолчанию такой же, как и в предыдущей строке; а для "табуляции надо продвигаться на 4 колонки" может быть что-то вроде (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 наконец-то научился "автоматически расширять список".

Но мне любопытно: почему бы просто не использовать существующие sml-mode это в GNU ELPA?

Другие вопросы по тегам