Skip to content

Commit

Permalink
Prevent line separators to be changed from CRLF to LF (#2752)
Browse files Browse the repository at this point in the history
When running on Windows, and `end_of_line` property not set in `.editorconfig` the line separators should not be changed from CRLF to LF whenever the file does not contain any lint violation that can be autocorrected.

Closes #2747
  • Loading branch information
paul-dingemans committed Jul 23, 2024
1 parent ce05eac commit 0b575a0
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ class KtLintRuleEngineTest {
@Nested
inner class `Format with KtLintRuleEngine` {
@Nested
inner class `Given a file that does not contain an error` {
inner class `Given a file that containing some errors` {
@Test
fun `Given defaultAutocorrect is not set`(
@TempDir
Expand Down Expand Up @@ -402,7 +402,7 @@ class KtLintRuleEngineTest {
}

@Nested
inner class `Given a kotlin code snippet that does contain an indentation error` {
inner class `Given a kotlin code snippet containing some errors` {
@Test
fun `Given defaultAutocorrect is not set`() {
val lintErrors = mutableListOf<LintError>()
Expand Down Expand Up @@ -511,7 +511,7 @@ class KtLintRuleEngineTest {
}

@Nested
inner class `Given a kotlin script code snippet that does contain an indentation error` {
inner class `Given a kotlin script code snippet containing some errors` {
@Test
fun `Given defaultAutocorrect is not set`() {
val lintErrors = mutableListOf<LintError>()
Expand Down Expand Up @@ -662,6 +662,51 @@ class KtLintRuleEngineTest {
""".trimIndent(),
)
}

@Test
fun `Issue 2747 - Given some code with crlf separators instead of lfs, but not containing any lint error, then do no reformat the line separators`(
@TempDir
tempDir: Path,
) {
val codeWithCrlfSeparators =
"""
fun bar() {
// FOO
// BAR
}
""".trimIndent().replace("\n", "\r\n")
val filePath = "$tempDir/Code.kt"
FileWriter(filePath).use {
it.write(codeWithCrlfSeparators)
}

val lintErrors = mutableListOf<LintError>()
val actual =
KtLintRuleEngine(
ruleProviders =
setOf(
RuleProvider { IndentationRule() },
RuleProvider { RuleWithAutocorrectApproveHandler() },
RuleProvider { RuleWithoutAutocorrectApproveHandler() },
),
editorConfigOverride =
EditorConfigOverride.from(
// Do not set END_OF_LINE_PROPERTY explicitly!
RULE_WITHOUT_AUTOCORRECT_APPROVE_HANDLER.createRuleExecutionEditorConfigProperty() to RuleExecution.enabled,
RULE_WITH_AUTOCORRECT_APPROVE_HANDLER.createRuleExecutionEditorConfigProperty() to RuleExecution.enabled,
),
fileSystem = ktlintTestFileSystem.fileSystem,
).format(
code = Code.fromFile(File(filePath)),
defaultAutocorrect = true,
) { lintError ->
lintErrors.add(lintError)
ALLOW_AUTOCORRECT
}

assertThat(lintErrors).isEmpty()
assertThat(actual).isEqualTo(codeWithCrlfSeparators)
}
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import com.pinterest.ktlint.rule.engine.core.api.Rule
import com.pinterest.ktlint.rule.engine.core.api.editorconfig.END_OF_LINE_PROPERTY
import io.github.oshai.kotlinlogging.KotlinLogging
import org.ec4j.core.model.PropertyType
import org.jetbrains.kotlin.util.prefixIfNot

private val LOGGER = KotlinLogging.logger {}.initKtLintKLogger()

Expand All @@ -30,7 +31,7 @@ internal class CodeFormatter(
.sortedWith(lintErrorLineAndColumnComparator { it.first })
.forEach { (e, corrected) -> callback(e, corrected) }

return (code.utf8Bom() + formattedCode).also {
return (formattedCode.prefixIfNot(code.utf8Bom())).also {
LOGGER.debug { "Finished with processing file '${code.fileNameOrStdin()}'" }
}
}
Expand Down Expand Up @@ -71,8 +72,13 @@ internal class CodeFormatter(
}
}
}
val lineSeparator = code.determineLineSeparator(editorConfig[END_OF_LINE_PROPERTY])
return Pair(formattedCode(lineSeparator), errors)
return if (mutated || formatRunCount > 1) {
val lineSeparator = code.determineLineSeparator(editorConfig[END_OF_LINE_PROPERTY])
Pair(formattedCode(lineSeparator), errors)
} else {
// None of the format runs has found
Pair(code.content, errors)
}
}
}

Expand Down Expand Up @@ -149,9 +155,9 @@ internal class CodeFormatter(
eolEditorConfigProperty == PropertyType.EndOfLineValue.crlf ||
eolEditorConfigProperty != PropertyType.EndOfLineValue.lf &&
doesNotContain('\r') ->
"\r\n".also { LOGGER.debug { "line separator: ${eolEditorConfigProperty.name} --> CRLF" } }
"\r\n".also { LOGGER.trace { "line separator: ${eolEditorConfigProperty.name} --> CRLF" } }

else -> "\n".also { LOGGER.debug { "line separator: ${eolEditorConfigProperty.name} --> LF" } }
else -> "\n".also { LOGGER.trace { "line separator: ${eolEditorConfigProperty.name} --> LF" } }
}

private fun Code.doesNotContain(char: Char) = content.lastIndexOf(char) != -1
Expand Down

0 comments on commit 0b575a0

Please sign in to comment.