Skip to content

Instantly share code, notes, and snippets.

@masm11
Last active May 26, 2019 04:33
Show Gist options
  • Save masm11/2d886459b5bdd266dab7ee7ebde6955a to your computer and use it in GitHub Desktop.
Save masm11/2d886459b5bdd266dab7ee7ebde6955a to your computer and use it in GitHub Desktop.
;;; Improved kotlin indentation.
;;;
;;; ~/.emacs:
;;;
;;; (with-eval-after-load 'kotlin-mode
;;; (require 'kotlin-indent))
;;;
(require 'paren)
(require 'font-lock)
(require 'text-property-search)
;; When the cursor is after a closing paren or brace,
;; return the position of opening one, or nil.
(defun kotlin-mode--masm11-indent-line--get-opening-paren ()
(let ((par (funcall show-paren-data-function)))
(and par
(not (nth 4 par))
(nth 2 par)))
)
;; With '// ...' comments ignored, do:
;; (if (looking-at REGEXP)
;; EXPR
;; FORM)
(defmacro kotlin-mode--masm11-indent-line--if-looking-at (regexp expr &rest form)
(declare (indent 2) (debug t))
`(let (b e m r)
(save-excursion
(save-restriction
(setq b (point))
(end-of-line)
(setq e (point))
(narrow-to-region b e)
(goto-char b)
(setq m (text-property-search-forward 'face font-lock-comment-face))
(when m
(narrow-to-region b (prop-match-end m)))
(goto-char b)
(setq m (text-property-search-forward 'face font-lock-comment-delimiter-face))
(when m
(narrow-to-region b (prop-match-end m)))
(goto-char b)
(setq r (looking-at ,regexp))
))
(if r
(progn ,expr)
(progn ,@form))
))
;; 'when' version of kotlin-mode--masm11-indent-line--if-looking-at.
(defmacro kotlin-mode--masm11-indent-line--when-looking-at (regexp &rest body)
(declare (indent defun) (debug t))
`(kotlin-mode--masm11-indent-line--if-looking-at ,regexp
(progn ,@body)))
;; Functions returning indentation.
;; If the line is beginning-of-buffer.
(defun kotlin-mode--masm11-indent-line--of-beginning-of-buffer ()
(when (bobp)
0
))
;; FooBar
;; .foo() // <--
;; .bar() // <--
(defun kotlin-mode--masm11-indent-line--starts-with-dot ()
(kotlin-mode--masm11-indent-line--when-looking-at "^[ \t]*\\."
(kotlin-mode--prev-line)
(kotlin-mode--masm11-indent-line--if-looking-at "^[ \t]*\\."
(current-indentation)
(+ (current-indentation) kotlin-tab-width))
))
;; if (foo) {
;; bar()
;; } // <--
(defun kotlin-mode--masm11-indent-line--starts-with-closing-brace ()
(kotlin-mode--masm11-indent-line--when-looking-at "^[ \t]*}"
(beginning-of-line)
(search-forward "}")
(let ((par (kotlin-mode--masm11-indent-line--get-opening-paren)))
(if (not par)
(current-indentation)
(goto-char par)
(current-indentation))))
)
;; foo(
;; 1,
;; 2
;; ) // <--
(defun kotlin-mode--masm11-indent-line--starts-with-closing-paren ()
(kotlin-mode--masm11-indent-line--when-looking-at "^[ \t]*)"
(beginning-of-line)
(search-forward ")")
(let ((par (kotlin-mode--masm11-indent-line--get-opening-paren)))
(if (not par)
(current-indentation)
(goto-char par)
(current-indentation))))
)
;; if (foo)
;; bar = 1
;; else // no opening braces.
;; bar = 2 // <--
;;
;; if (foo) {
;; bar = 1
;; } else
;; bar = 2 // <--
(defun kotlin-mode--masm11-indent-line--starts-with-previous-line-ending-with-else ()
(kotlin-mode--prev-line)
(end-of-line)
(backward-word)
(kotlin-mode--masm11-indent-line--when-looking-at "else"
(+ (current-indentation) kotlin-tab-width)
))
;; if (foo) // no braces
;; bar = 2 // <--
;; else if (baz) // no braces
;; bar = 3 // <--
(defun kotlin-mode--masm11-indent-line--starts-with-previous-line-ending-with-closing-paren ()
(kotlin-mode--prev-line)
(kotlin-mode--masm11-indent-line--when-looking-at ".*)[ \t]*$"
(end-of-line)
(search-backward ")")
(forward-char)
(let ((par (kotlin-mode--masm11-indent-line--get-opening-paren)))
(when par
(goto-char par)
(backward-word)
(kotlin-mode--masm11-indent-line--if-looking-at "if\\|while\\|for"
(+ (current-indentation) kotlin-tab-width)
)))))
;; Looking far from this line.
(defun kotlin-mode--masm11-indent-line--others ()
(catch 'indented
(while t
(kotlin-mode--prev-line)
;; if (foo) {
;; bar() // <--
;; baz() // <--
(kotlin-mode--masm11-indent-line--when-looking-at ".*{[ \t]*$"
(throw 'indented (+ (current-indentation) kotlin-tab-width)))
;; if (foo) {
;; }
;; bar() // <--
;; baz() // <--
(kotlin-mode--masm11-indent-line--when-looking-at "^[ \t]*}"
(throw 'indented (current-indentation)))
;; foo { _, _ ->
;; bar() // <--
;; baz() // <--
(kotlin-mode--masm11-indent-line--when-looking-at ".*{.*->[ \t]*$"
(throw 'indented (+ (current-indentation) kotlin-tab-width)))
;; foo(
;; 1, // <--
;; 2 // <--
;; )
(kotlin-mode--masm11-indent-line--when-looking-at ".*([ \t]*$"
(throw 'indented (+ (current-indentation) kotlin-tab-width)))
;; foo(
;; 1,
;; 2
;; )
;; bar() // <--
;; baz() // <--
(kotlin-mode--masm11-indent-line--when-looking-at "^[ \t]*).*$"
(throw 'indented (current-indentation)))
(when (bobp)
(throw 'indented (current-indentation)))
)))
;; Otherwise...
(defun kotlin-mode--masm11-indent-line--sentinel ()
(kotlin-mode--prev-line)
(current-indentation)
)
(defun kotlin-mode--masm11-indent-line ()
"Indent current line as kotlin code"
(let* ((funcs '(kotlin-mode--masm11-indent-line--of-beginning-of-buffer
kotlin-mode--masm11-indent-line--starts-with-dot
kotlin-mode--masm11-indent-line--starts-with-closing-brace
kotlin-mode--masm11-indent-line--starts-with-closing-paren
kotlin-mode--masm11-indent-line--starts-with-previous-line-ending-with-else
kotlin-mode--masm11-indent-line--starts-with-previous-line-ending-with-closing-paren
kotlin-mode--masm11-indent-line--others
kotlin-mode--masm11-indent-line--sentinel))
(indent (save-excursion
(beginning-of-line)
(catch 'indented
(dolist (func funcs)
(save-excursion
(let ((indent (funcall func)))
(when indent
; (message (format "%s" func))
(throw 'indented indent)))))))))
(indent-line-to indent)))
(add-hook 'kotlin-mode-hook
(function
(lambda ()
(setq indent-line-function 'kotlin-mode--masm11-indent-line))))
(provide 'kotlin-indent)
;;;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment