Skip to content

Commit

Permalink
Add CLI --help option (#477)
Browse files Browse the repository at this point in the history
Summary:
Intended to land on top of #476

Pull Request resolved: #477

Reviewed By: cortinico

Differential Revision: D58448561

Pulled By: hick209

fbshipit-source-id: 28762cf9a9f40c88d981cb493b0c2f8299e9e622
  • Loading branch information
Joseph Cooper authored and facebook-github-bot committed Jun 13, 2024
1 parent 8f09ecb commit cf8eac3
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 6 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).

### Added
- Created CHANGELOG.md
- Added --help option to CLI (https://github.com/facebook/ktfmt/pull/477)

### Changed
- Preserves blank spaces between when clauses (https://github.com/facebook/ktfmt/issues/342)
Expand Down
15 changes: 11 additions & 4 deletions core/src/main/java/com/facebook/ktfmt/cli/Main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,13 @@ private const val EXIT_CODE_SUCCESS = 0

private val USAGE =
"""
Usage: ktfmt [--meta-style | --google-style | --kotlinlang-style] [--dry-run] [--set-exit-if-changed] [--stdin-name=<name>] [--do-not-remove-unused-imports] File1.kt File2.kt ...
Or: ktfmt @file
"""
.trimIndent()
|Usage:
| ktfmt [OPTIONS] File1.kt File2.kt ...
| ktfmt @ARGFILE
|
|For more details see `ktfmt --help`
|"""
.trimMargin()

class Main(
private val input: InputStream,
Expand Down Expand Up @@ -80,6 +83,10 @@ class Main(
val parsedArgs =
when (processArgs) {
is ParseResult.Ok -> processArgs.parsedValue
is ParseResult.ShowMessage -> {
out.println(processArgs.message)
return EXIT_CODE_SUCCESS
}
is ParseResult.Error -> {
err.println(processArgs.errorMessage)
return EXIT_CODE_FAILURE
Expand Down
52 changes: 52 additions & 0 deletions core/src/main/java/com/facebook/ktfmt/cli/ParsedArgs.kt
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,54 @@ data class ParsedArgs(
return parseOptions(arguments)
}

val HELP_TEXT =
"""
|ktfmt - command line Kotlin source code pretty-printer
|
|Usage:
| ktfmt [OPTIONS] <File1.kt> <File2.kt> ...
| ktfmt @ARGFILE
|
|ktfmt formats Kotlin source code files in-place, reporting for each file whether the
|formatting succeeded or failed on standard error. If none of the style options are
|passed, Meta's style is used.
|
|Alternatively, ktfmt can read Kotlin source code from standard input and write the
|formatted result on standard output.
|
|Example:
| $ ktfmt --kotlinlang-style Main.kt src/Parser.kt
| Done formatting Main.kt
| Error formatting src/Parser.kt: @@@ERROR@@@; skipping.
|
|Commands options:
| -h, --help Show this help message
| -n, --dry-run Don't write to files, only report files which
| would have changed
| --meta-style Use 2-space block indenting (default)
| --google-style Google internal style (2 spaces)
| --kotlinlang-style Kotlin language guidelines style (4 spaces)
| --stdin-name=<name> Name to report when formatting code from stdin
| --set-exit-if-changed Sets exit code to 1 if any input file was not
| formatted/touched
| --do-not-remove-unused-imports Leaves all imports in place, even if not used
|
|ARGFILE:
| If the only argument begins with '@', the remainder of the argument is treated
| as the name of a file to read options and arguments from, one per line.
|
| e.g.
| $ cat arg-file.txt
| --google-style
| -n
| File1.kt
| File2.kt
| $ ktfmt @arg-file1.txt
| Done formatting File1.kt
| Done formatting File2.kt
|"""
.trimMargin()

/** parseOptions parses command-line arguments passed to ktfmt. */
fun parseOptions(args: Array<out String>): ParseResult {
val fileNames = mutableListOf<String>()
Expand All @@ -57,6 +105,8 @@ data class ParsedArgs(
var removeUnusedImports = true
var stdinName: String? = null

if ("--help" in args || "-h" in args) return ParseResult.ShowMessage(HELP_TEXT)

for (arg in args) {
when {
arg == "--meta-style" -> formattingOptions = Formatter.META_FORMAT
Expand Down Expand Up @@ -108,5 +158,7 @@ data class ParsedArgs(
sealed interface ParseResult {
data class Ok(val parsedValue: ParsedArgs) : ParseResult

data class ShowMessage(val message: String) : ParseResult

data class Error(val errorMessage: String) : ParseResult
}
14 changes: 14 additions & 0 deletions core/src/test/java/com/facebook/ktfmt/cli/MainTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -493,4 +493,18 @@ class MainTest {
assertThat(exitCode).isEqualTo(0)
assertThat(file.readText(UTF_8)).isEqualTo("""fun f() = println("hello, world")""" + "\n")
}

@Test
fun `--help gives return code of 0`() {
val exitCode =
Main(
emptyInput,
PrintStream(out),
PrintStream(err),
arrayOf("--help"),
)
.run()

assertThat(exitCode).isEqualTo(0)
}
}
19 changes: 19 additions & 0 deletions core/src/test/java/com/facebook/ktfmt/cli/ParsedArgsTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,25 @@ class ParsedArgsTest {
assertThat(parseResult).isInstanceOf(ParseResult.Error::class.java)
}

@Test
fun `parseOptions recognises --help`() {
val parseResult = ParsedArgs.parseOptions(arrayOf("--help"))
assertThat(parseResult).isInstanceOf(ParseResult.ShowMessage::class.java)
}

@Test
fun `parseOptions recognises -h`() {
val parseResult = ParsedArgs.parseOptions(arrayOf("-h"))
assertThat(parseResult).isInstanceOf(ParseResult.ShowMessage::class.java)
}

@Test
fun `arg --help overrides all others`() {
val parseResult =
ParsedArgs.parseOptions(arrayOf("--style=google", "@unknown", "--help", "file.kt"))
assertThat(parseResult).isInstanceOf(ParseResult.ShowMessage::class.java)
}

@Test
fun `processArgs use the @file option with non existing file`() {
val e =
Expand Down
6 changes: 4 additions & 2 deletions online_formatter/src/main/kotlin/main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@ class Handler : RequestHandler<APIGatewayProxyRequestEvent, String> {
try {
val request = gson.fromJson(event.body, Request::class.java)
val style = request.style
val parseResult = ParsedArgs.parseOptions(listOfNotNull(style).toTypedArray())
when (parseResult) {
when (val parseResult = ParsedArgs.parseOptions(listOfNotNull(style).toTypedArray())) {
is ParseResult.Ok -> {
val parsedArgs = parseResult.parsedValue
Response(
Expand All @@ -51,6 +50,9 @@ class Handler : RequestHandler<APIGatewayProxyRequestEvent, String> {
is ParseResult.Error -> {
Response(null, parseResult.errorMessage)
}
is ParseResult.ShowMessage -> {
Response(null, parseResult.message)
}
}
} catch (e: Exception) {
Response(null, e.message)
Expand Down

0 comments on commit cf8eac3

Please sign in to comment.