-
-
Notifications
You must be signed in to change notification settings - Fork 107
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Resolves #58 Detect indent from EditorConfig file
- Loading branch information
Jean-Michel Fayard
committed
Sep 10, 2019
1 parent
47ef29f
commit 16332f6
Showing
16 changed files
with
277 additions
and
53 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
package de.fayard | ||
|
||
import java.io.File | ||
|
||
data class Section(val name: String, val lines: MutableList<Pair<String, String>>) { | ||
operator fun get(key: String): String? { | ||
return lines.firstOrNull { it.first == key }?.second | ||
} | ||
} | ||
|
||
object EditorConfig { | ||
const val NAME = ".editorconfig" | ||
const val INDENT_STYLE = "indent_style" | ||
const val INDENT_SIZE = "indent_size" | ||
const val SPACE = "space" | ||
const val TAB = "tab" | ||
|
||
fun findIndentForKotlin(fromDir: File) : String? { | ||
return findEditorConfig(fromDir) | ||
.flatMap { file -> file.parseSections() } | ||
.findIndentForKotlinFiles() | ||
} | ||
|
||
fun List<Section>.findIndentForKotlinFiles() : String? { | ||
val section = this.sortedByDescending { it.priority() } | ||
.filter { s -> | ||
s[INDENT_STYLE] != null && s.priority() > 0 | ||
}.firstOrNull() | ||
return section?.findIndent() | ||
} | ||
|
||
fun Section.findIndent() : String? { | ||
val size = this[INDENT_SIZE]?.toIntOrNull() | ||
val style = this[INDENT_STYLE] | ||
return when { | ||
style == TAB -> "\t" | ||
style == SPACE && size != null -> List(size) { " " }.joinToString(separator = "") | ||
else -> null | ||
} | ||
} | ||
|
||
|
||
fun File.isRootEditorConfig() : Boolean = when { | ||
name != NAME -> false | ||
this.exists().not() -> false | ||
else -> readLines().any { it.replace(" ", "").contains("root=true") } | ||
} | ||
|
||
fun Section.priority() = when { | ||
name.contains("kt") -> 4 | ||
name.contains("gradle") -> 3 | ||
name.contains("java") -> 2 | ||
name == "*" -> 1 | ||
else -> -1 | ||
} | ||
|
||
fun File.parseSections(): List<Section> { | ||
assert(name == NAME) | ||
assert(canRead()) | ||
val result = mutableListOf<Section>() | ||
var currentSection: Section? = null | ||
readLines().map { line -> | ||
line.substringBefore("#").substringBefore(";") | ||
}.forEach { line -> | ||
val section = line.parseSection() | ||
val split = line.split("=").map { it.trim() } | ||
when { | ||
section != null -> { | ||
currentSection = Section(section, mutableListOf()) | ||
result.add(currentSection!!) | ||
} | ||
currentSection == null || line.isBlank() || split.size != 2 -> { } | ||
else -> currentSection!!.lines.add(split.first() to split.last()) | ||
} | ||
} | ||
return result | ||
} | ||
|
||
fun String.parseSection() : String? { | ||
val section = this.substringAfter("[", "").substringBefore("]", "").trim() | ||
return if (section.isBlank()) null else section | ||
} | ||
|
||
fun findEditorConfig(fromDir: File) : List<File> { | ||
val result = mutableListOf<File>() | ||
var current: File? = fromDir | ||
while (current != null) { | ||
val ec = current.resolve(NAME) | ||
if (ec.exists()) { | ||
assert(ec.name == NAME) | ||
result += ec | ||
} | ||
if (ec.isRootEditorConfig()) { | ||
break | ||
} | ||
current = current.parentFile | ||
} | ||
return result | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
package de.fayard | ||
|
||
import io.kotlintest.matchers.haveSize | ||
import io.kotlintest.matchers.withClue | ||
import io.kotlintest.should | ||
import io.kotlintest.shouldBe | ||
import io.kotlintest.specs.FreeSpec | ||
import io.kotlintest.tables.forAll | ||
import io.kotlintest.tables.headers | ||
import io.kotlintest.tables.row | ||
import io.kotlintest.tables.table | ||
import java.io.File | ||
|
||
|
||
|
||
class EditorConfigTest: FreeSpec({ | ||
val testFolder = File("src/test/resources").absoluteFile | ||
|
||
"Project Dir" { | ||
withClue(testFolder.absolutePath) { | ||
testFolder.name shouldBe "resources" | ||
} | ||
} | ||
|
||
"Find files" { | ||
val table = table( | ||
headers("path", "expected size"), | ||
row("a/b/c", 3), | ||
row("a/b", 2), | ||
row("a", 1), | ||
row("libs", 2) | ||
) | ||
|
||
table.forAll { path, expectedSize -> | ||
val list = EditorConfig.findEditorConfig(testFolder.resolve(path)) | ||
withClue(list.toString()) { list should haveSize(expectedSize) } | ||
} | ||
} | ||
|
||
"Sections" { | ||
with(EditorConfig) { | ||
val sections = testResourceFile("a/b/.editorconfig").parseSections() | ||
withClue(sections.toString()) { | ||
sections.size shouldBe 2 | ||
val (kotlin, python) = sections | ||
python shouldBe Section("*.py", mutableListOf("indent_style" to "tab", "insert_final_newline" to "true")) | ||
kotlin shouldBe Section("*.kt", mutableListOf("indent_style" to "space", "indent_size" to "4")) | ||
kotlin[INDENT_STYLE] shouldBe "space" | ||
kotlin[INDENT_SIZE] shouldBe "4" | ||
kotlin["insert_final_newline"] shouldBe null | ||
} | ||
} | ||
} | ||
|
||
with(EditorConfig) { | ||
"Parse Indents" - { | ||
"Tabs" { | ||
val section = Section("*", mutableListOf(INDENT_STYLE to TAB, "key" to "value")) | ||
section.findIndent() shouldBe "\t" | ||
} | ||
"Four spaces" { | ||
val section = Section("*", mutableListOf(INDENT_STYLE to SPACE, "key" to "value", INDENT_SIZE to "4")) | ||
section.findIndent() shouldBe " " | ||
} | ||
"Two spaces" { | ||
val section = Section("*", mutableListOf(INDENT_STYLE to SPACE, "key" to "value", INDENT_SIZE to "2")) | ||
section.findIndent() shouldBe " " | ||
} | ||
"space no size: invalid" { | ||
val section = Section("*", mutableListOf(INDENT_STYLE to SPACE, "key" to "value")) | ||
section.findIndent() shouldBe null | ||
} | ||
"no information" { | ||
val section = Section("*", mutableListOf( "key" to "value")) | ||
section.findIndent() shouldBe null | ||
} | ||
} | ||
} | ||
|
||
"Find indentation for Kotlin" { | ||
val table = table( | ||
headers("path", "indentation"), | ||
row("libs", " "), | ||
row("a", " "), | ||
row("a/b", " "), | ||
row("a/b/c", " "), | ||
row("maven", null) | ||
) | ||
table.forAll { path, expectedIndent -> | ||
EditorConfig.findIndentForKotlin(testFolder.resolve(path)) shouldBe expectedIndent | ||
} | ||
} | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
[*] | ||
indent_style = space | ||
indent_size = 2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
root = true | ||
|
||
[*.{java,kt,kts}] | ||
indent_style = space ; comment | ||
indent_size = 3 # comment | ||
|
||
# comment |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
[*.kt] | ||
indent_style = space | ||
indent_size = 4 # 2 is better | ||
|
||
# 4 space indentation | ||
[*.py] | ||
indent_style = tab | ||
insert_final_newline = true | ||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
[*.java] | ||
indent_style = space | ||
indent_size = 5 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
root = true | ||
|
||
[*.py] | ||
indent_style = space | ||
indent_size = 2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.