[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[nongnu] elpa/kotlin-mode d6720fe9bc 123/162: Merge pull request #40 fro
From: |
ELPA Syncer |
Subject: |
[nongnu] elpa/kotlin-mode d6720fe9bc 123/162: Merge pull request #40 from martinblake/master |
Date: |
Sat, 29 Jan 2022 08:25:29 -0500 (EST) |
branch: elpa/kotlin-mode
commit d6720fe9bc2ce447f213c470bd18fad8e04dc18b
Merge: 0e542ae2f7 5e9aff2ae9
Author: Gregg Hernandez <greggory.hz@gmail.com>
Commit: GitHub <noreply@github.com>
Merge pull request #40 from martinblake/master
Indentation Improvements
---
kotlin-mode.el | 244 +++++++++++++++++++++++++++++++++--------------
test/kotlin-mode-test.el | 74 ++++++++++----
test/sample.kt | 124 ++++++++++++++----------
3 files changed, 305 insertions(+), 137 deletions(-)
diff --git a/kotlin-mode.el b/kotlin-mode.el
index 143cc880e4..e5c7b92373 100644
--- a/kotlin-mode.el
+++ b/kotlin-mode.el
@@ -28,6 +28,8 @@
(require 'comint)
(require 'rx)
(require 'cc-cmds)
+(require 'cl)
+(require 'eieio)
(defgroup kotlin nil
"A Kotlin major mode."
@@ -128,7 +130,6 @@
(define-key map (kbd "C-c C-r") 'kotlin-send-region)
(define-key map (kbd "C-c C-c") 'kotlin-send-block)
(define-key map (kbd "C-c C-b") 'kotlin-send-buffer)
- (define-key map (kbd "<tab>") 'c-indent-line-or-region)
map)
"Keymap for kotlin-mode")
@@ -173,7 +174,7 @@
"when" "is" "in" "as" "return"))
(defconst kotlin-mode--context-variables-keywords
- '("this" "super"))
+ '("field" "it" "this" "super"))
(defvar kotlin-mode--keywords
(append kotlin-mode--misc-keywords
@@ -193,7 +194,7 @@
"annotation" "internal" "const" "in" "out")) ;; "in" "out"
(defconst kotlin-mode--property-keywords
- '("by")) ;; "by" "get" "set"
+ '("by" "get" "set")) ;; "by" "get" "set"
(defconst kotlin-mode--initializer-keywords
'("init" "constructor"))
@@ -257,11 +258,11 @@
;; Properties
;; by/get/set are valid identifiers being used as variable
- ;; TODO: Highlight keywords in the property declaration statement
- ;; (,(rx-to-string
- ;; `(and bow (group (or ,@kotlin-mode--property-keywords)) eow)
- ;; t)
- ;; 1 font-lock-keyword-face)
+ ;; TODO: Highlight only within the property declaration statement
+ (,(rx-to-string
+ `(and bow (group (or ,@kotlin-mode--property-keywords)) eow)
+ t)
+ 1 font-lock-keyword-face)
;; Constructor/Initializer blocks
(,(rx-to-string
@@ -324,70 +325,175 @@
(while (and (looking-at "^[ \t]*$") (not (bobp)))
(forward-line -1)))))
+(defun kotlin-mode--line-begins (pattern)
+ "Return whether the current line begins with the given pattern"
+ (save-excursion
+ (beginning-of-line)
+ (looking-at (format "^[ \t]*%s" pattern))))
+
+(defun kotlin-mode--line-ends (pattern)
+ "Return whether the current line ends with the given pattern"
+ (save-excursion
+ (beginning-of-line)
+ (looking-at (format ".*%s[ \t]*$" pattern))))
+
+(defun kotlin-mode--line-contains (pattern)
+ "Return whether the current line contains the given pattern"
+ (save-excursion
+ (beginning-of-line)
+ (looking-at (format ".*%s.*" pattern))))
+
+(defun kotlin-mode--line-continuation()
+ "Return whether this line continues a statement in the previous line"
+ (or
+ (kotlin-mode--line-begins "\\([\.=:]\\|->\\|[sg]et\\b\\)")
+ (save-excursion
+ (kotlin-mode--prev-line)
+ (kotlin-mode--line-ends "\\([=:]\\|->\\)"))))
+
+(defun kotlin-mode--base-indentation ()
+ "Return the indentation level of the current line based on brackets only,
+ i.e. ignoring 'continuation' indentation."
+ (cond ((kotlin-mode--line-continuation)
+ (- (current-indentation) kotlin-tab-width))
+ ((kotlin-mode--in-comment-block)
+ (- (current-indentation) 1))
+ (t
+ (current-indentation))))
+
+(defclass kotlin-mode--bracket-counter ()
+ ((count :initarg :count
+ :initform 0
+ :type integer
+ :documentation "The net bracket count (+1 for open, -1 for close).")
+ (indent :initarg :indent
+ :initform 0
+ :type integer
+ :documentation "The indentation based on bracket layout.")
+ (finished :initarg :finished
+ :initform nil
+ :type boolean
+ :documentation "Whether the counting has finished.")
+ (use-base :initarg :use-base
+ :initform t
+ :type boolean
+ :documentation "Whether to factor out extra indentations."))
+ "A class for counting brackets to find the appropriate bracket-based indent.
+ The logic here involves keeping track of the net-bracket-count,
+ defined as the number of open-brackets minus the number of close-brackets.
+ We scroll backwards until the net-bracket-count is zero, and this point
+ determines the desired indentation level for the current line.")
+
+(cl-defmethod count-to-line-start ((counter kotlin-mode--bracket-counter))
+ "Count the brackets on the current line, starting from the cursor
+ position, and working backward, incrementing the count
+ +1 for open-brackets, -1 for close-brackets.
+ Return as soon as the overall count exceeds zero."
+ (save-excursion
+ (while (and (<= (oref counter count) 0) (not (bolp)))
+ (backward-char)
+ (cond ((looking-at "\\s\(")
+ (oset counter count (+ (oref counter count) 1)))
+ ((looking-at "\\s\)")
+ (oset counter count (- (oref counter count) 1)))))
+ (cond
+ ;; If the net-bracket-count is zero, use this indentation
+ ((= (oref counter count) 0)
+ (oset counter finished t)
+ (if (oref counter use-base)
+ (add-indent counter (kotlin-mode--base-indentation))
+ (add-indent counter (current-indentation))))
+ ;; If we've now counted more open-brackets than close-brackets,
+ ;; use the indentation of the content immediately following the
+ ;; final open-bracket.
+ ((> (oref counter count) 0)
+ (oset counter finished t)
+ (forward-char)
+ (skip-syntax-forward "(")
+ (skip-syntax-forward "-")
+ (let (position)
+ (setq position (point))
+ (add-indent counter (- position (re-search-backward "^"))))))))
+
+(cl-defmethod count-leading-close-brackets
+ ((counter kotlin-mode--bracket-counter))
+ "Count any close-bracket at the start of the current line."
+ (if (looking-at "\\s\)")
+ (oset counter use-base nil))
+ (subtract-count counter (skip-syntax-forward ")")))
+
+(cl-defmethod count-trailing-open-brackets
+ ((counter kotlin-mode--bracket-counter))
+ "If the bracket count is at zero, and there are open-brackets at the end
+ of the line, do not count them, but add a single indentation level."
+ (if (= (oref counter count) 0)
+ (cond ((not (= (skip-syntax-backward "(") 0))
+ (add-indent counter kotlin-tab-width)
+ (oset counter use-base nil)))))
+
+(cl-defmethod add-count ((counter kotlin-mode--bracket-counter) val)
+ (oset counter count (+ (oref counter count) val)))
+
+(cl-defmethod subtract-count ((counter kotlin-mode--bracket-counter) val)
+ (oset counter count (- (oref counter count) val)))
+
+(cl-defmethod add-indent ((counter kotlin-mode--bracket-counter) val)
+ (oset counter indent (+ (oref counter indent) val)))
+
+(cl-defmethod finished ((counter kotlin-mode--bracket-counter))
+ (oref counter finished))
+
+
+(defun kotlin-mode--in-comment-block ()
+ "Return whether the cursor is within a standard comment block structure
+ of the following format:
+ /**
+ * Description here
+ */ "
+ (save-excursion
+ (let ((in-comment-block nil)
+ (keep-going (not (kotlin-mode--line-ends "\\*\\*/"))))
+ (while keep-going
+ (kotlin-mode--prev-line)
+ (cond
+ ((bobp)
+ (setq keep-going nil))
+ ((kotlin-mode--line-contains "\\*/")
+ (setq keep-going nil))
+ ((kotlin-mode--line-begins "/\\*")
+ (setq keep-going nil)
+ (setq in-comment-block t))))
+ in-comment-block)))
+
(defun kotlin-mode--indent-line ()
- "Indent current line as kotlin code"
+ "Indent current line as kotlin code."
(interactive)
(beginning-of-line)
- (if (bobp) ; 1.)
- (progn
- (kotlin-mode--beginning-of-buffer-indent))
- (let ((not-indented t) cur-indent)
- (cond ((looking-at "^[ \t]*\\.") ; line starts with .
- (save-excursion
- (kotlin-mode--prev-line)
- (cond ((looking-at "^[ \t]*\\.")
- (setq cur-indent (current-indentation)))
-
- (t
- (setq cur-indent (+ (current-indentation) (* 2
kotlin-tab-width)))))
- (if (< cur-indent 0)
- (setq cur-indent 0))))
-
- ((looking-at "^[ \t]*}") ; line starts with }
- (save-excursion
- (kotlin-mode--prev-line)
- (while (and (or (looking-at "^[ \t]*$") (looking-at "^[
\t]*\\.")) (not (bobp)))
- (kotlin-mode--prev-line))
- (cond ((or (looking-at ".*{[ \t]*$") (looking-at ".*{.*->[
\t]*$"))
- (setq cur-indent (current-indentation)))
- (t
- (setq cur-indent (- (current-indentation)
kotlin-tab-width)))))
- (if (< cur-indent 0)
- (setq cur-indent 0)))
-
- ((looking-at "^[ \t]*)") ; line starts with )
- (save-excursion
- (kotlin-mode--prev-line)
- (setq cur-indent (- (current-indentation) kotlin-tab-width)))
- (if (< cur-indent 0)
- (setq cur-indent 0)))
-
- (t
- (save-excursion
- (while not-indented
- (kotlin-mode--prev-line)
- (cond ((looking-at ".*{[ \t]*$") ; line ends with {
- (setq cur-indent (+ (current-indentation)
kotlin-tab-width))
- (setq not-indented nil))
-
- ((looking-at "^[ \t]*}") ; line starts with }
- (setq cur-indent (current-indentation))
- (setq not-indented nil))
-
- ((looking-at ".*{.*->[ \t]*$") ; line ends with ->
- (setq cur-indent (+ (current-indentation)
kotlin-tab-width))
- (setq not-indented nil))
-
- ((looking-at ".*([ \t]*$") ; line ends with (
- (setq cur-indent (+ (current-indentation)
kotlin-tab-width))
- (setq not-indented nil))
-
- ((looking-at "^[ \t]*).*$") ; line starts with )
- (setq cur-indent (current-indentation))
- (setq not-indented nil))
-
- ((bobp) ; 5.)
- (setq not-indented nil)))))))
+ (if (bobp)
+ (kotlin-mode--beginning-of-buffer-indent)
+ (let ((cur-indent 0))
+ ;; Find bracket-based indentation first
+ (let ((bracket-counter (kotlin-mode--bracket-counter)))
+ (save-excursion
+ (skip-syntax-forward "-")
+ (count-leading-close-brackets bracket-counter))
+ (save-excursion
+ (progn (kotlin-mode--prev-line) (end-of-line))
+ (count-trailing-open-brackets bracket-counter)
+ (count-to-line-start bracket-counter)
+ (while (and (not (finished bracket-counter)) (not (bobp)))
+ (progn (kotlin-mode--prev-line) (end-of-line))
+ (count-to-line-start bracket-counter)
+ )
+ (incf cur-indent (oref bracket-counter indent))))
+
+ (cond ((kotlin-mode--line-continuation)
+ ;; Add extra indentation if the line continues the previous one
+ (incf cur-indent kotlin-tab-width))
+ ((kotlin-mode--in-comment-block)
+ ;; Add one space of extra indentation if inside a comment block
+ (incf cur-indent)))
+
(if cur-indent
(indent-line-to cur-indent)
(indent-line-to 0)))))
diff --git a/test/kotlin-mode-test.el b/test/kotlin-mode-test.el
index c75137cd3b..5329d00afa 100644
--- a/test/kotlin-mode-test.el
+++ b/test/kotlin-mode-test.el
@@ -1,3 +1,7 @@
+;; Tests assume a tab is represented by 4 spaces
+(setq-default indent-tabs-mode nil)
+(setq-default tab-width 4)
+
(load-file "kotlin-mode.el")
;(require 'kotlin-mode)
@@ -44,31 +48,61 @@ return a + b
(kotlin-mode--indent-line)
(should (equal (buffer-string) "fun sum(a: Int, b: Int): Int {
- return a + b
+ return a + b
}")))))
-;; (ert-deftest kotlin-mode--chained-methods ()
-;; (with-temp-buffer
-;; (let ((text "names.filter { it.empty }
-;; .sortedBy { it }
-;; .map { it.toUpperCase() }
-;; .forEach { print(it) }"))
+(ert-deftest kotlin-mode--chained-methods ()
+ (with-temp-buffer
+ (let ((text "names.filter { it.empty }
+.sortedBy { it }
+.map { it.toUpperCase() }
+.forEach { print(it) }"))
+
+ (insert text)
+ (beginning-of-buffer)
+
+ (kotlin-mode--indent-line)
-;; (insert text)
-;; (beginning-of-buffer)
+ (next-line)
+ (kotlin-mode--indent-line)
-;; (kotlin-mode--indent-line)
+ (next-line)
+ (kotlin-mode--indent-line)
+
+ (next-line)
+ (kotlin-mode--indent-line)
+
+ (should (equal (buffer-string) "names.filter { it.empty }
+ .sortedBy { it }
+ .map { it.toUpperCase() }
+ .forEach { print(it) }")))))
+
+(defun next-non-empty-line ()
+ "Moves to the next non-empty line"
+ (forward-line)
+ (while (and (looking-at "^[ \t]*$") (not (eobp)))
+ (forward-line)))
+
+(ert-deftest kotlin-mode--sample-test ()
+ (with-temp-buffer
+ (insert-file-contents "test/sample.kt")
+ (beginning-of-buffer)
+ (while (not (eobp))
+ (let ((expected-line (thing-at-point 'line)))
-;; (next-line)
-;; (kotlin-mode--indent-line)
+ ;; Remove existing indentation
+ (beginning-of-line)
+ (delete-region (point) (progn (skip-chars-forward " \t") (point)))
-;; (next-line)
-;; (kotlin-mode--indent-line)
+ ;; Indent the line
+ (kotlin-mode--indent-line)
-;; (next-line)
-;; (kotlin-mode--indent-line)
+ ;; Check that the correct indentation is re-applied
+ (should (equal expected-line (thing-at-point 'line)))
-;; (should (equal (buffer-string) "names.filter { it.empty }
-;; .sortedBy { it }
-;; .map { it.toUpperCase() }
-;; .forEach { print(it) }")))))
\ No newline at end of file
+ ;; Go to the next non-empty line
+ (next-non-empty-line)
+ )
+ )
+ )
+ )
diff --git a/test/sample.kt b/test/sample.kt
index 069c879711..06a8063dfc 100644
--- a/test/sample.kt
+++ b/test/sample.kt
@@ -6,9 +6,14 @@ import bar.Bar as bBar
// a single line comment
-/*
-* a multiline comment
-*/
+/**
+ * a multiline comment
+ */
+
+/****************************************************************
+ Multiline comment
+ without leading "*"
+****************************************************************/
fun sum(a: Int, b: Int): Int {
return a + b
@@ -21,7 +26,16 @@ fun printSum(a: Int, b: Int): Unit {
}
fun printSum(a: Int, b: Int) {
- print(a + b)
+ val veryLongResultVariableName: Int
+ = (a + b)
+ print(veryLongResultVariableName)
+}
+
+fun functionMultiLineArgs(first: Int,
+ second: Int,
+ third: Int,
+ fourth: Int) {
+ print("(${first}, ${second}, ${third}, ${fourth})")
}
val a: Int = 1
@@ -105,14 +119,14 @@ if (text in names) // names.contains(text) is called
print("Yes")
names.filter { it.startsWith("A") }
- .sortedBy { it }
- .map { it.toUpperCase() }
- .forEach { print(it) }
+ .sortedBy { it }
+ .map { it.toUpperCase() }
+ .forEach { print(it) }
fun f() {
things.f()
- .g()
- .h()
+ .g()
+ .h()
}
data class Customer(val name: String, val email: String)
@@ -191,18 +205,19 @@ class Turtle {
}
val myTurtle = Turtle()
-with(myTurtle) { //draw a 100 pix square
-penDown()
-for(i in 1..4) {
- forward(100.0)
- turn(90.0)
-}
-penUp()
+with(myTurtle) {
+ //draw a 100 pix square
+ penDown()
+ for(i in 1..4) {
+ forward(100.0)
+ turn(90.0)
+ }
+ penUp()
}
val stream = Files.newInputStream(Paths.get("/some/file.txt"))
-stream.buffered().reader().use { reader ->
- println(reader.readText())
+stream.buffered().reader().use {
+ reader -> println(reader.readText())
}
inline fun <reified T: Any> Gson.fromJson(json): T = this.fromJson(json,
T::class.java)
@@ -287,7 +302,9 @@ class Derived() : Base() {
override fun v() {}
}
-open class AnotherDerived() : Base() {
+open class AnotherDerived()
+ : Base()
+{
final override fun v() {}
}
@@ -310,7 +327,7 @@ interface B {
}
class C() : A(), B {
- // The compiler requires f() to be overridden:
+ // The compiler requires f() to be overridden
override fun f() {
super<A>.f() // call to A.f()
super<B>.f() // call to B.f()
@@ -339,10 +356,10 @@ fun eval(expr: Expr): Double = when(expr) {
}
var stringRepresentation: String
-get() = this.toString()
-set(value) {
- setDataFromString(value) // parses the string and assigns values to other
properties
-}
+ get() = this.toString()
+ set(value) {
+ setDataFromString(value) // parses the string and assigns values to
other properties
+ }
var setterVisibility: String = "abc"
private set // the setter is private and has the default implementation
@@ -351,13 +368,13 @@ var setterWithAnnotation: Any? = null
@Inject set // annotate the setter with Inject
var counter = 0 // the initializer value is written directly to the backing
field
-set(value) {
- if (value >= 0)
- field = value
-}
+ set(value) {
+ if (value >= 0)
+ field = value
+ }
val isEmpty: Boolean
-get() = this.size == 0
+ get() = this.size == 0
const val SUBSYSTEM_DEPRECATED: String = "This subsystem is deprecated"
@@ -392,7 +409,7 @@ interface MyInterface {
val property: Int // abstract
val propertyWithImplementation: String
- get() = "foo"
+ get() = "foo"
fun foo() {
print(property)
@@ -462,7 +479,7 @@ fun Any?.toString(): String {
}
val <T> List<T>.lastIndex: Int
-get() = size - 1
+ get() = size - 1
class MyClass {
companion object { } // will be called "Companion"
@@ -563,14 +580,15 @@ enum class ProtocolState {
abstract fun signal(): ProtocolState
}
-window.addMouseListener(object : MouseAdapter() {
- override fun mouseClicked(e: MouseEvent) {
- // ...
- }
+window.addMouseListener(
+ object : MouseAdapter() {
+ override fun mouseClicked(e: MouseEvent) {
+ // ...
+ }
- override fun mouseEntered(e: MouseEvent) {
- // ...
- }
+ override fun mouseEntered(e: MouseEvent) {
+ // ...
+ }
})
val adHoc = object {
@@ -583,14 +601,15 @@ fun countClicks(window: JComponent) {
var clickCount = 0
var enterCount = 0
- window.addMouseListener(object : MouseAdapter() {
- override fun mouseClicked(e: MouseEvent) {
- clickCount++
- }
+ window.addMouseListener(
+ object : MouseAdapter() {
+ override fun mouseClicked(e: MouseEvent) {
+ clickCount++
+ }
- override fun mouseEntered(e: MouseEvent) {
- enterCount++
- }
+ override fun mouseEntered(e: MouseEvent) {
+ enterCount++
+ }
})
// ...
}
@@ -634,7 +653,7 @@ fun <T> asList(vararg ts: T): List<T> {
}
tailrec fun findFixPoint(x: Double = 1.0): Double
-= if (x == Math.cos(x)) x else findFixPoint(Math.cos(x))
+ = if (x == Math.cos(x)) x else findFixPoint(Math.cos(x))
fun <T> lock(lock: Lock, body: () -> T): T {
lock.lock()
@@ -707,8 +726,16 @@ inline fun <reified T> TreeNode.findParentOfType(): T? {
}
class Test {
- fun f() {
-
+ fun tryAdd(a: Int?, b: Int?) : Int? {
+ var result: Int? = null
+ a?.let {
+ lhs ->
+ b?.let {
+ rhs ->
+ result = lhs + rhs
+ }
+ }
+ return result
}
}
@@ -718,3 +745,4 @@ fun itpl() {
print("${foo}bar");
print("${`weird$! identifier`}bar");
}
+
- [nongnu] elpa/kotlin-mode 39db5b6208 033/162: kotlin-mode: Highlight properties, (continued)
- [nongnu] elpa/kotlin-mode 39db5b6208 033/162: kotlin-mode: Highlight properties, ELPA Syncer, 2022/01/29
- [nongnu] elpa/kotlin-mode 300acc2341 036/162: kotlin-mode: Highlight package names, ELPA Syncer, 2022/01/29
- [nongnu] elpa/kotlin-mode a174f5ba44 039/162: kotlin-mode: Add kotlin-mode--match-interpolation, ELPA Syncer, 2022/01/29
- [nongnu] elpa/kotlin-mode 42b7af8122 046/162: 'data class' -> 'data', ELPA Syncer, 2022/01/29
- [nongnu] elpa/kotlin-mode 6c5531cd6f 059/162: Add autoload cookie to the kotlin-mode, ELPA Syncer, 2022/01/29
- [nongnu] elpa/kotlin-mode 876cc27dc1 159/162: Merge pull request #63 from phikal/patch-1, ELPA Syncer, 2022/01/29
- [nongnu] elpa/kotlin-mode a51321a4d1 161/162: Merge pull request #64 from phst/license, ELPA Syncer, 2022/01/29
- [nongnu] elpa/kotlin-mode 8e4018e7a5 044/162: Added new keywords to kotlin-mode, ELPA Syncer, 2022/01/29
- [nongnu] elpa/kotlin-mode fdadc96898 034/162: kotlin-mode: Defin initializer keywords, ELPA Syncer, 2022/01/29
- [nongnu] elpa/kotlin-mode c3942942a8 066/162: Merge branch 'patch-1' of https://github.com/jasonm23/kotlin-mode, ELPA Syncer, 2022/01/29
- [nongnu] elpa/kotlin-mode d6720fe9bc 123/162: Merge pull request #40 from martinblake/master,
ELPA Syncer <=
- [nongnu] elpa/kotlin-mode fd099c806b 134/162: Propertize multiline strings, ELPA Syncer, 2022/01/29
- [nongnu] elpa/kotlin-mode 0649b358f2 141/162: Make compatible with 24.3, ELPA Syncer, 2022/01/29
- [nongnu] elpa/kotlin-mode 653f82488c 149/162: Merge pull request #48 from taku0/fix-for-24.3, ELPA Syncer, 2022/01/29