Search code examples
emacsprogramming-languageslispindentationmode

Creating emacs mode: defining indentation


I'm writing a simple mode for a Lisp-like language, and am having trouble setting up indentation. I've been following the emacswiki mode tutorial.

However, I can't figure out how to adapt their example indentation to my needs because they don't do any form of counting.

Basically, I just need to add 2 spaces to my indentation count every time I see a { or (, even if there are multiple on the same line, and subtract 2 spaces when I see closures of the above. I'm new to elisp; how can I adapt their example to count braces and brackets?

For convenience, here is the code they are using (for a non-bracket language):

(defun wpdl-indent-line ()
  "Indent current line as WPDL code"
  (interactive)
  (beginning-of-line)
  (if (bobp)  ; Check for rule 1
      (indent-line-to 0)
    (let ((not-indented t) cur-indent)
      (if (looking-at "^[ \t]*END_") ; Check for rule 2
      (progn
        (save-excursion
          (forward-line -1)
          (setq cur-indent (- (current-indentation) default-tab-width)))
        (if (< cur-indent 0)
        (setq cur-indent 0)))
        (save-excursion 
          (while not-indented
            (forward-line -1)
            (if (looking-at "^[ \t]*END_") ; Check for rule 3
                (progn
                  (setq cur-indent (current-indentation))
                  (setq not-indented nil))
                    ; Check for rule 4
              (if (looking-at "^[ \t]*\\(PARTICIPANT\\|MODEL\\|APPLICATION\\|WORKFLOW\\|ACTIVITY\\|DATA\\|TOOL_LIST\\|TRANSITION\\)")
                  (progn
                    (setq cur-indent (+ (current-indentation) default-tab-width))
                    (setq not-indented nil))
                (if (bobp) ; Check for rule 5
                    (setq not-indented nil)))))))
      (if cur-indent
          (indent-line-to cur-indent)
        (indent-line-to 0))))) ; If we didn't see an indentation hint, then allow no indentation

How can I just implement lisp-like indentation (but also with curly braces)?


Solution

  • If you want something simple for a Lisp-style language, I suggest you start with (syntax-ppss) which returns the "parsing state" at point. The first element of that state is the current paren-nesting depth. While I used the word "paren", this doesn't really count parens but counts those chars which the syntax-table defines as paren-like, so if you set your syntax-table such that { and } are declared as paren-like, then those will also be counted.

    So you could start with something like

    (defun foo-indent-function ()
      (save-excursion
        (beginning-of-line)
        (indent-line-to (* 2 (car (syntax-ppss))))))
    

    Do not define this as interactive, since the way to use it is by adding

    (set (make-local-variable 'indent-line-function) #'foo-indent-function)
    

    in your major-mode function.

    But maybe a better option is to simply do:

    (require 'smie)
    ...
    (define-derived-mode foo-mode "Foo"
      ...
      (smie-setup nil #'ignore)
      ...)
    

    This will use an indentation step of 4 (configured in smie-indent-basic).