Skip to content

Commit

Permalink
Always use UTF8 as the encoding for Kotlin code, regardless of the sy…
Browse files Browse the repository at this point in the history
…stem/default charset

Closes #373
  • Loading branch information
nreid260 committed Jan 18, 2024
1 parent 7d28ad1 commit 6daea70
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 66 deletions.
7 changes: 7 additions & 0 deletions core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,13 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>-Dfile.encoding=UTF-16</argLine>
</configuration>
</plugin>
</plugins>
</build>

Expand Down
53 changes: 28 additions & 25 deletions core/src/main/java/com/facebook/ktfmt/cli/Main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,22 @@ import com.facebook.ktfmt.format.Formatter
import com.facebook.ktfmt.format.ParseError
import com.google.googlejavaformat.FormattingError
import java.io.BufferedReader
import java.io.BufferedWriter
import java.io.File
import java.io.FileInputStream
import java.io.IOException
import java.io.InputStream
import java.io.InputStreamReader
import java.io.OutputStreamWriter
import java.io.PrintStream
import java.nio.charset.StandardCharsets.UTF_8
import java.util.concurrent.atomic.AtomicInteger
import kotlin.system.exitProcess

class Main(
private val input: InputStream,
private val out: PrintStream,
private val err: PrintStream,
private val stdin: InputStream,
private val stdout: PrintStream,
private val stderr: PrintStream,
args: Array<String>
) {
companion object {
Expand Down Expand Up @@ -65,13 +69,13 @@ class Main(
}
}

private val parsedArgs: ParsedArgs = ParsedArgs.processArgs(err, args)
private val parsedArgs: ParsedArgs = ParsedArgs.processArgs(stderr, args)

fun run(): Int {
fun run(): Int {
if (parsedArgs.fileNames.isEmpty()) {
err.println(
stderr.println(
"Usage: ktfmt [--dropbox-style | --google-style | --kotlinlang-style] [--dry-run] [--set-exit-if-changed] [--stdin-name=<name>] [--do-not-remove-unused-imports] File1.kt File2.kt ...")
err.println("Or: ktfmt @file")
stderr.println("Or: ktfmt @file")
return 1
}

Expand All @@ -83,20 +87,20 @@ class Main(
1
}
} else if (parsedArgs.stdinName != null) {
err.println("Error: --stdin-name can only be used with stdin")
stderr.println("Error: --stdin-name can only be used with stdin")
return 1
}

val files: List<File>
try {
files = expandArgsToFileNames(parsedArgs.fileNames)
} catch (e: java.lang.IllegalStateException) {
err.println(e.message)
stderr.println(e.message)
return 1
}

if (files.isEmpty()) {
err.println("Error: no .kt files found")
stderr.println("Error: no .kt files found")
return 1
}

Expand All @@ -117,59 +121,58 @@ class Main(
* Handles the logic for formatting and flags.
*
* If dry run mode is active, this simply prints the name of the [source] (file path or `<stdin>`)
* to [out]. Otherwise, this will run the appropriate formatting as normal.
* to [stdout]. Otherwise, this will run the appropriate formatting as normal.
*
* @param file The file to format. If null, the code is read from <stdin>.
* @return true iff input is valid and already formatted.
*/
private fun format(file: File?): Boolean {
val fileName = file?.toString() ?: parsedArgs.stdinName ?: "<stdin>"
try {
val code = file?.readText() ?: BufferedReader(InputStreamReader(input)).readText()
val input = if (file == null) stdin else FileInputStream(file)
val code = BufferedReader(InputStreamReader(input, UTF_8)).readText()
val formattedCode = Formatter.format(parsedArgs.formattingOptions, code)
val alreadyFormatted = code == formattedCode

// stdin
if (file == null) {
if (parsedArgs.dryRun) {
if (!alreadyFormatted) {
out.println(fileName)
stderr.println(fileName)
}
} else {
out.print(formattedCode)
BufferedWriter(OutputStreamWriter(stdout, UTF_8)).use {
it.write(formattedCode)
}
}
return alreadyFormatted
}

if (parsedArgs.dryRun) {
if (!alreadyFormatted) {
out.println(fileName)
stderr.println(fileName)
}
} else {
// TODO(T111284144): Add tests
if (!alreadyFormatted) {
file.writeText(formattedCode)
file.writeText(formattedCode, UTF_8)
}
err.println("Done formatting $fileName")
stderr.println("Done formatting $fileName")
}

return alreadyFormatted
} catch (e: IOException) {
err.println("Error formatting $fileName: ${e.message}; skipping.")
stderr.println("Error formatting $fileName: ${e.message}; skipping.")
throw e
} catch (e: ParseError) {
handleParseError(fileName, e)
stderr.println("$fileName:${e.message}")
throw e
} catch (e: FormattingError) {
for (diagnostic in e.diagnostics()) {
System.err.println("$fileName:$diagnostic")
stderr.println("$fileName:$diagnostic")
}
e.printStackTrace(err)
e.printStackTrace(stderr)
throw e
}
}

private fun handleParseError(fileName: String, e: ParseError) {
err.println("$fileName:${e.message}")
}
}
3 changes: 2 additions & 1 deletion core/src/main/java/com/facebook/ktfmt/cli/ParsedArgs.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import com.facebook.ktfmt.format.Formatter
import com.facebook.ktfmt.format.FormattingOptions
import java.io.File
import java.io.PrintStream
import java.nio.charset.StandardCharsets.UTF_8

/** ParsedArgs holds the arguments passed to ktfmt on the command-line, after parsing. */
data class ParsedArgs(
Expand All @@ -40,7 +41,7 @@ data class ParsedArgs(

fun processArgs(err: PrintStream, args: Array<String>): ParsedArgs {
if (args.size == 1 && args[0].startsWith("@")) {
return parseOptions(err, File(args[0].substring(1)).readLines().toTypedArray())
return parseOptions(err, File(args[0].substring(1)).readLines(UTF_8).toTypedArray())
} else {
return parseOptions(err, args)
}
Expand Down
Loading

0 comments on commit 6daea70

Please sign in to comment.