Introduce Compose ktlint rules (#267)

This commit is contained in:
Jake Wharton
2023-12-01 22:03:15 -05:00
committed by GitHub
parent 6883845130
commit 12fc6fc245
14 changed files with 65 additions and 55 deletions

View File

@ -56,11 +56,17 @@ allprojects {
spotless { spotless {
kotlin { kotlin {
target("src/**/*.kt") target("src/**/*.kt")
ktlint(libs.ktlint.get().version).editorConfigOverride([ ktlint(libs.ktlint.core.get().version)
'ktlint_standard_filename': 'disabled', .editorConfigOverride([
'ktlint_standard_property-naming': 'disabled', 'ktlint_standard_filename': 'disabled',
'ktlint_function_naming_ignore_when_annotated_with': 'Composable', 'ktlint_standard_property-naming': 'disabled',
]) 'ktlint_function_naming_ignore_when_annotated_with': 'Composable',
'ktlint_compose_modifier-missing-check': 'disabled',
'ktlint_compose_compositionlocal-allowlist': 'disabled',
])
.customRuleSets([
libs.ktlint.composeRules.get().toString(),
])
} }
} }
} }

View File

@ -18,7 +18,8 @@ buildconfig-gradlePlugin = "com.github.gmazzo.buildconfig:plugin:4.2.0"
poko-gradlePlugin = "dev.drewhamilton.poko:poko-gradle-plugin:0.15.1" poko-gradlePlugin = "dev.drewhamilton.poko:poko-gradle-plugin:0.15.1"
spotless-gradlePlugin = "com.diffplug.spotless:spotless-plugin-gradle:6.23.2" spotless-gradlePlugin = "com.diffplug.spotless:spotless-plugin-gradle:6.23.2"
ktlint = "com.pinterest.ktlint:ktlint-cli:1.0.1" ktlint-core = "com.pinterest.ktlint:ktlint-cli:1.0.1"
ktlint-composeRules = "io.nlopez.compose.rules:ktlint:0.3.3"
jansi = "org.fusesource.jansi:jansi:2.4.1" jansi = "org.fusesource.jansi:jansi:2.4.1"
mordant = "com.github.ajalt.mordant:mordant:2.2.0" mordant = "com.github.ajalt.mordant:mordant:2.2.0"

View File

@ -99,7 +99,7 @@ internal class MosaicNode(
override var parentData: Any? = null override var parentData: Any? = null
private set private set
var modifiers: Modifier = Modifier var modifier: Modifier = Modifier
set(value) { set(value) {
topLayer = value.foldOut(bottomLayer) { element, lowerLayer -> topLayer = value.foldOut(bottomLayer) { element, lowerLayer ->
when (element) { when (element) {

View File

@ -28,7 +28,7 @@ public fun Box(
val measurePolicy = rememberBoxMeasurePolicy(contentAlignment, propagateMinConstraints) val measurePolicy = rememberBoxMeasurePolicy(contentAlignment, propagateMinConstraints)
Layout( Layout(
content = { BoxScopeInstance.content() }, content = { BoxScopeInstance.content() },
modifiers = modifier, modifier = modifier,
debugInfo = { "Box(alignment=$contentAlignment, propagateMinConstraints=$propagateMinConstraints)" }, debugInfo = { "Box(alignment=$contentAlignment, propagateMinConstraints=$propagateMinConstraints)" },
measurePolicy = measurePolicy, measurePolicy = measurePolicy,
) )

View File

@ -20,7 +20,7 @@ public fun Column(
val measurePolicy = columnMeasurePolicy(verticalArrangement, horizontalAlignment) val measurePolicy = columnMeasurePolicy(verticalArrangement, horizontalAlignment)
Layout( Layout(
content = { ColumnScopeInstance.content() }, content = { ColumnScopeInstance.content() },
modifiers = modifier, modifier = modifier,
debugInfo = { "Column(arrangement=$verticalArrangement, alignment=$horizontalAlignment)" }, debugInfo = { "Column(arrangement=$verticalArrangement, alignment=$horizontalAlignment)" },
measurePolicy = measurePolicy, measurePolicy = measurePolicy,
) )

View File

@ -37,15 +37,16 @@ internal sealed class NoContentMeasureScope {
@Composable @Composable
@MosaicComposable @MosaicComposable
@Suppress("ktlint:compose:param-order-check") // Order is correct, check just can't tell.
internal fun Layout( internal fun Layout(
modifiers: Modifier = Modifier, modifier: Modifier = Modifier,
debugInfo: () -> String = { "Layout()" }, debugInfo: () -> String = { "Layout()" },
measurePolicy: NoContentMeasurePolicy, measurePolicy: NoContentMeasurePolicy,
) { ) {
Node( Node(
measurePolicy = NoContentMeasurePolicyMeasurePolicy(measurePolicy), measurePolicy = NoContentMeasurePolicyMeasurePolicy(measurePolicy),
modifiers = modifiers, modifier = modifier,
debugPolicy = { debugInfo() + " x=$x y=$y w=$width h=$height${modifiers.toDebugString()}" }, debugPolicy = { debugInfo() + " x=$x y=$y w=$width h=$height${modifier.toDebugString()}" },
factory = NodeFactory, factory = NodeFactory,
) )
} }
@ -63,20 +64,21 @@ private class NoContentMeasurePolicyMeasurePolicy(
} }
@Composable @Composable
@Suppress("ktlint:compose:param-order-check") // Order is what we want.
public fun Layout( public fun Layout(
content: @Composable () -> Unit, content: @Composable () -> Unit,
modifiers: Modifier = Modifier, modifier: Modifier = Modifier,
debugInfo: () -> String = { "Layout()" }, debugInfo: () -> String = { "Layout()" },
measurePolicy: MeasurePolicy, measurePolicy: MeasurePolicy,
) { ) {
Node( Node(
content = content, content = content,
measurePolicy = measurePolicy, measurePolicy = measurePolicy,
modifiers = modifiers, modifier = modifier,
debugPolicy = { debugPolicy = {
buildString { buildString {
append(debugInfo()) append(debugInfo())
append(" x=$x y=$y w=$width h=$height${modifiers.toDebugString()}") append(" x=$x y=$y w=$width h=$height${modifier.toDebugString()}")
children.joinTo(this, separator = "") { children.joinTo(this, separator = "") {
"\n" + it.toString().prependIndent(" ") "\n" + it.toString().prependIndent(" ")
} }

View File

@ -14,11 +14,12 @@ import com.jakewharton.mosaic.ui.unit.Constraints
@Composable @Composable
@MosaicComposable @MosaicComposable
@Suppress("ktlint") // TODO why doesn't "ktlint:compose:param-order-check" work here?
internal inline fun Node( internal inline fun Node(
content: content:
@Composable @MosaicComposable @Composable @MosaicComposable
() -> Unit = {}, () -> Unit = {},
modifiers: Modifier, modifier: Modifier,
measurePolicy: MeasurePolicy, measurePolicy: MeasurePolicy,
debugPolicy: DebugPolicy, debugPolicy: DebugPolicy,
noinline factory: () -> MosaicNode, noinline factory: () -> MosaicNode,
@ -27,7 +28,7 @@ internal inline fun Node(
factory = factory, factory = factory,
update = { update = {
set(measurePolicy) { this.measurePolicy = measurePolicy } set(measurePolicy) { this.measurePolicy = measurePolicy }
set(modifiers) { this.modifiers = modifiers } set(modifier) { this.modifier = modifier }
set(debugPolicy) { this.debugPolicy = debugPolicy } set(debugPolicy) { this.debugPolicy = debugPolicy }
}, },
content = content, content = content,

View File

@ -20,7 +20,7 @@ public fun Row(
val measurePolicy = rowMeasurePolicy(horizontalArrangement, verticalAlignment) val measurePolicy = rowMeasurePolicy(horizontalArrangement, verticalAlignment)
Layout( Layout(
content = { RowScopeInstance.content() }, content = { RowScopeInstance.content() },
modifiers = modifier, modifier = modifier,
debugInfo = { "Row(arrangement=$horizontalArrangement, alignment=$verticalAlignment)" }, debugInfo = { "Row(arrangement=$horizontalArrangement, alignment=$verticalAlignment)" },
measurePolicy = measurePolicy, measurePolicy = measurePolicy,
) )

View File

@ -17,11 +17,11 @@ import com.jakewharton.mosaic.ui.unit.Constraints
*/ */
@Composable @Composable
@NonRestartableComposable @NonRestartableComposable
public fun Spacer(modifier: Modifier) { public fun Spacer(modifier: Modifier = Modifier) {
Layout( Layout(
content = EmptySpacerContent, content = EmptySpacerContent,
measurePolicy = SpacerMeasurePolicy, measurePolicy = SpacerMeasurePolicy,
modifiers = modifier, modifier = modifier,
debugInfo = { "Spacer()" }, debugInfo = { "Spacer()" },
) )
} }

View File

@ -44,7 +44,7 @@ public fun <T> Static(
} }
} }
}, },
modifiers = Modifier, modifier = Modifier,
debugPolicy = { debugPolicy = {
children.joinToString(prefix = "Static()") { "\n" + it.toString().prependIndent(" ") } children.joinToString(prefix = "Static()") { "\n" + it.toString().prependIndent(" ") }
}, },

View File

@ -31,7 +31,7 @@ public fun Text(
layout.measure() layout.measure()
layout(layout.width, layout.height) layout(layout.width, layout.height)
}, },
modifiers = modifier.drawBehind { modifier = modifier.drawBehind {
layout.lines.forEachIndexed { row, line -> layout.lines.forEachIndexed { row, line ->
drawText(row, 0, line, color, background, style) drawText(row, 0, line, color, background, style)
} }
@ -59,7 +59,7 @@ public fun Text(
layout.measure() layout.measure()
layout(layout.width, layout.height) layout(layout.width, layout.height)
}, },
modifiers = modifier.drawBehind { modifier = modifier.drawBehind {
layout.lines.forEachIndexed { row, line -> layout.lines.forEachIndexed { row, line ->
drawText(row, 0, line, color, background, style) drawText(row, 0, line, color, background, style)
} }

View File

@ -27,7 +27,7 @@ class DebugRenderingTest {
val nodes = mosaicNodes { val nodes = mosaicNodes {
Row { Row {
Text("Hello ") Text("Hello ")
Layout(modifiers = Modifier.drawBehind { throw UnsupportedOperationException() }) { Layout(modifier = Modifier.drawBehind { throw UnsupportedOperationException() }) {
layout(5, 1) layout(5, 1)
} }
} }

View File

@ -105,7 +105,7 @@ class LayoutTest {
Row { Row {
Text("..") Text("..")
Layout( Layout(
modifiers = Modifier.drawBehind { modifier = Modifier.drawBehind {
repeat(4) { row -> repeat(4) { row ->
drawText(row, 0, "XXXX") drawText(row, 0, "XXXX")
} }

View File

@ -2,7 +2,6 @@ package example
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
@ -150,9 +149,8 @@ fun Log(complete: SnapshotStateList<Test>) {
} }
@Composable @Composable
fun Status(tests: List<Test>) { fun Status(tests: SnapshotStateList<Test>) {
val running by derivedStateOf { tests.filter { it.state == Running } } val running = tests.filter { it.state == Running }
if (running.isNotEmpty()) { if (running.isNotEmpty()) {
for (test in running) { for (test in running) {
TestRow(test) TestRow(test)
@ -163,8 +161,8 @@ fun Status(tests: List<Test>) {
} }
@Composable @Composable
private fun Summary(totalTests: Int, tests: List<Test>) { private fun Summary(totalTests: Int, tests: SnapshotStateList<Test>) {
val counts by derivedStateOf { tests.groupingBy { it.state }.eachCount() } val counts = tests.groupingBy { it.state }.eachCount()
val failed = counts[Fail] ?: 0 val failed = counts[Fail] ?: 0
val passed = counts[Pass] ?: 0 val passed = counts[Pass] ?: 0
val running = counts[Running] ?: 0 val running = counts[Running] ?: 0
@ -179,39 +177,41 @@ private fun Summary(totalTests: Int, tests: List<Test>) {
} }
} }
Text( Column {
buildAnnotatedString { Text(
append("Tests: ") buildAnnotatedString {
append("Tests: ")
if (failed > 0) { if (failed > 0) {
withStyle(SpanStyle(color = Red)) { withStyle(SpanStyle(color = Red)) {
append("$failed failed") append("$failed failed")
}
append(", ")
} }
append(", ")
}
if (passed > 0) { if (passed > 0) {
withStyle(SpanStyle(color = Green)) { withStyle(SpanStyle(color = Green)) {
append("$passed passed") append("$passed passed")
}
append(", ")
} }
append(", ")
}
if (running > 0) { if (running > 0) {
withStyle(SpanStyle(color = Yellow)) { withStyle(SpanStyle(color = Yellow)) {
append("$running running") append("$running running")
}
append(", ")
} }
append(", ")
}
append("$totalTests total") append("$totalTests total")
}, },
) )
Text("Time: ${elapsed}s") Text("Time: ${elapsed}s")
if (running > 0) { if (running > 0) {
TestProgress(totalTests, passed, failed, running) TestProgress(totalTests, passed, failed, running)
}
} }
} }