0

The special file format of my software uses angle brackets as a delimiter and # / # as comment markers (note the whitespace after the first # and before the last #). I try to make a major mode to handle those files. I notice that the definition of the whitespace as a following character of the # enters in conflict with the indentation and font lock. I used the same syntax of my comment syntax table than the C/C++ style with /* and */.

The MWE mode is

(defvar my-very-basic-mode-syntax-table nil
  "Syntax table for `my-very-basic-mode'.")

;; My syntax table
(setq my-very-basic-mode-syntax-table
  (let ((my-very-basic-table (make-syntax-table)))
    ; Delimiters
    (modify-syntax-entry ?\{ "(}" my-very-basic-table)
    (modify-syntax-entry ?\} "){" my-very-basic-table)
    ; Comments
    (modify-syntax-entry ?# ". 14" my-very-basic-table)
    ;(modify-syntax-entry ? ". 23" my-very-basic-table) ; THE PROBLEM

    my-very-basic-table))

;; My indentation function
(defvar my-very-basic-mode-indent-offset 2
  "Indentation offset for `MY-VERY-BASIC-mode'.")

(defun my-very-basic-mode-indent-line ()
  "Indent current line for `MY-VERY-BASIC-mode'."
  (interactive)
  (let ((indent-col 0))
    (save-excursion
      (beginning-of-line)
      (condition-case nil
          (while t
            (backward-up-list 1)
            (when (looking-at "[[{]")
              (setq indent-col (+ indent-col my-very-basic-mode-indent-offset))))
        (error nil)))
    (save-excursion
      (back-to-indentation)
      (when (and (looking-at "[]}]") (>= indent-col my-very-basic-mode-indent-offset))
        (setq indent-col (- indent-col my-very-basic-mode-indent-offset))))
    (indent-line-to indent-col)))

;; = My basic font-lock
(setq my-very-basic-font-lock
      (let* ((x-comments '("# " " #"))
             (x-comments-regexp (regexp-opt x-comments 'words)))
        `((,x-comments-regexp . 'font-lock-comment-face))))

;; My simple mode
(define-derived-mode my-very-basic-mode text-mode "my-very-basic-mode"
  "Mode for editing some kind of config files."

  (setq-local comment-start "# ")
  (setq-local comment-end " #")
  (make-local-variable 'my-very-basic-mode-indent-offset)
  (set (make-local-variable 'indent-line-function) 'my-very-basic-mode-indent-line)
  (set-syntax-table my-very-basic-mode-syntax-table)
  (setq-local font-lock-defaults '((my-very-basic-font-lock))))

;; Myformat
(add-to-list 'auto-mode-alist '("\\.myformat\\'" . my-very-basic-mode))

;; = End of mode
(provide 'my-very-basic-mode)
;;; my-very-basic-mode.el ends here

When I comment this line (modify-syntax-entry ? ". 23" my-very-basic-table) ; THE PROBLEM, I have a proper indentation but not the gray comment font (in file.myformat) :

# a block # <- NOT GRAY
{
  an internal block {
    some text {
      temperature 300
    } <- GOOD INDENTATION
  }
}

But if I uncomment the problematic line, it mixes with the indent calculation :

# a block # <- GRAY
{
  an internal block {
    some text {
      temperature 300
      } <- BAD INDENTATION
    }
}

Indent function is not my own, but I cannot find the source any more, unfortunately. My knowledge of Elisp is not that strong, and I cannot figure out what is missing. Any clue how to mix the two? I tried escaping with ?\ but that did not change. Any clue on how to make everything work together?

1 Answer 1

0

I finally took some time to investigate this, thanks to the awesome Emacs debugger. The problem was this exact line (modify-syntax-entry ? ". 23" my-very-basic-table). That . in the syntax entry modified whitespace character to punctuation, spotted thanks to C-h s. So when (back-to-excursion) was called, there was an issue in the condition (looking-at "[}]") if the rbrace was not on the first column. The condition was thus nil and the indentation was not decremented. I changed to (modify-syntax-entry ? "- 23" my-very-basic-table) and it is now a nice whitespace. And it works like a charm now.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.