~jakob/myrddin-mode

cb46614d09a5a0f0ef49efdff9a88bea6372a91a — Jakob L. Kreuze 4 years ago bcd03d1
Fix issues with indentation.

- Anything at the beginning of a file was screwed up.
- Match arms were screwed up.
1 files changed, 57 insertions(+), 28 deletions(-)

M myrddin-mode.el
M myrddin-mode.el => myrddin-mode.el +57 -28
@@ 145,38 145,67 @@
;;; Indentation.
;;;

(defun myrddin-mode--preceding-nonempty-line ()
  "Return the text of and the indentation level of the closest
preceding line that does not consist entirely of whitespace, or
NIL if there is no preceding line."
  (unless (bobp)
    (save-excursion
      (let (last-line)
        (while (not (and last-line (plusp (length (string-trim last-line)))))
          (previous-line)
          (back-to-indentation)
          (setf last-line (buffer-substring-no-properties
                           (line-beginning-position)
                           (line-end-position))))
        (values last-line (/ (current-column) myrddin-indent-offset))))))


(defun myrddin-mode--nearest-match-level ()
  (save-excursion
    (while (not (or (bobp) (looking-at "match")))
      (previous-line)
      (back-to-indentation))
    (/ (current-column) myrddin-indent-offset)))

(defun myrddin-mode--calculate-indent (prev-line prev-level)
  (save-excursion
    (back-to-indentation)
    (cond
     ;; Handle match arms by finding the indentation of the nearest match
     ;; statement.
     ((looking-at (rx ?|))
      (* myrddin-indent-offset (myrddin-mode--nearest-match-level)))
     ;; Deindent any lines beginning with a syntactic element for closing a
     ;; block, unless it occurs immediately following the beginning of a block.
     ((looking-at (rx (or "}" ";;" "elif" "else")))
      (if (string-match-p
           (rx (eval (cons 'or (cons "{" myrddin-mode-block-keywords))))
           prev-line)
          (* myrddin-indent-offset prev-level)
        (max 0 (* myrddin-indent-offset (1- prev-level)))))
     ;; Indent any lines immediately following a line containing a syntactic
     ;; element for opening a block.
     ((string-match-p
       (rx (eval (cons 'or (append '("|" "{") myrddin-mode-block-keywords))))
       prev-line)
      (* myrddin-indent-offset (1+ prev-level)))
     (t (* myrddin-indent-offset prev-level)))))

(defun myrddin-mode-indent-line ()
  "Indent current line for Myrddin mode.
Return the amount the indentation changed by."
  (interactive)
  (let* ((prev-level (save-excursion
                       (forward-line -1)
                       (back-to-indentation)
                       (/ (current-column) myrddin-indent-offset)))
         (prev-line (save-excursion
                      (forward-line -1)
                      (back-to-indentation)
                      (buffer-substring-no-properties
                       (line-beginning-position)
                       (line-end-position)))))
    (let ((indent
           (save-excursion
             (back-to-indentation)
             (cond
              ((looking-at
                (rx (or "}" ";;" "elif" "else")))
               (max 0 (* myrddin-indent-offset (1- prev-level))))
              ((string-match-p
                (rx (or "{" "elif" "else" "for" "if" "match"
                        "struct" "trait" "while"))
                prev-line)
               (* myrddin-indent-offset (1+ prev-level)))
              (t (* myrddin-indent-offset prev-level))))))

      (if (<= (current-column) (current-indentation))
          (indent-line-to indent)
        (save-excursion (indent-line-to indent)))
      indent)))
  (let ((prev-line (myrddin-mode--preceding-nonempty-line)))
    (if prev-line
        (cl-destructuring-bind (prev-line prev-level) prev-line
            (let ((indent (myrddin-mode--calculate-indent prev-line prev-level)))
              (when indent
                (if (<= (current-column) (current-indentation))
                    (indent-line-to indent)
                  (save-excursion (indent-line-to indent))))))
      ;; The first line in the file should begin on column 0.
      (indent-line-to 0))))


;;;