Skip to content

Commit

Permalink
Add --stdin-path to provide a virtual file location for stdin (#2836)
Browse files Browse the repository at this point in the history
Fixes #1123

---------

Co-authored-by: Alex Decker <[email protected]>
Co-authored-by: Paul Dingemans <[email protected]>
  • Loading branch information
3 people authored Oct 19, 2024
1 parent 11f01c1 commit 80c4d5d
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 7 deletions.
9 changes: 7 additions & 2 deletions documentation/snapshot/docs/install/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,9 +168,14 @@ ktlint --stdin -F
```

!!! tip "Suppress logging and error output"
Logging output printed to `stdout` can be suppressed by setting `--log-level=none` (see [logging](#logging)).
Output printed to `stderr` can be suppressed in different ways. To ignore all error output, add `2> /dev/null` to the end of the command line. Otherwise, specify a [reporter](#violation-reporting) to write the error output to a file.
Logging output printed to `stdout` can be suppressed by setting `--log-level=none` (see [logging](#logging)).
Output printed to `stderr` can be suppressed in different ways. To ignore all error output, add `2> /dev/null` to the end of the command line. Otherwise, specify a [reporter](#violation-reporting) to write the error output to a file.

If input from `stdin` represents the contents of a file, the file path can be supplied with `stdin-path`. This path is made available for rules to use, the `--format` option will not modify this file.

```shell title="file path from stdin-path"
ktlint --stdin --stdin-path /path/to/file/Foo.kt
```

### Git hooks

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,12 @@ internal class KtlintCommandLine : CliktCommand(name = "ktlint") {
help = "Read file from stdin",
).flag()

private val stdinPath: String? by
option(
"--stdin-path",
help = "Virtual file location for stdin. When combined with option '--format' the actual file will not be overwritten",
)

private val patternsFromStdin: String? by
option(
"--patterns-from-stdin",
Expand Down Expand Up @@ -263,7 +269,7 @@ internal class KtlintCommandLine : CliktCommand(name = "ktlint") {
val editorConfigOverride =
EditorConfigOverride
.EMPTY_EDITOR_CONFIG_OVERRIDE
.applyIf(stdin) {
.applyIf(stdin && stdinPath.isNullOrBlank()) {
logger.debug {
"Add editor config override to disable 'filename' rule which can not be used in combination with reading from " +
"<stdin>"
Expand Down Expand Up @@ -427,11 +433,17 @@ internal class KtlintCommandLine : CliktCommand(name = "ktlint") {
ktLintRuleEngine: KtLintRuleEngine,
reporter: ReporterV2,
) {
val code =
stdinPath
?.expandTildeToFullPath()
?.let { path -> Paths.get(path) }
?.let { Code.fromStdin(it) }
?: Code.fromStdin()
report(
KtLintRuleEngine.STDIN_FILE,
process(
ktLintRuleEngine = ktLintRuleEngine,
code = Code.fromStdin(),
code = code,
baselineLintErrors = emptyList(),
),
reporter,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,21 @@ class SimpleCLITest {
}
}

@Test
fun `Issue 1123 - Enable filename rule when --stdin and --stdin-path is used`(
@TempDir
tempDir: Path,
) {
CommandLineTestRunner(tempDir)
.run(
testProjectName = "too-many-empty-lines",
arguments = listOf("--stdin", "--stdin-path", "/foo/Foo.kt"),
stdin = ByteArrayInputStream("fun foo() = 42".toByteArray()),
) {
assertThat(normalOutput).doesNotContainLineMatching(Regex(".*ktlint_standard_filename: disabled.*"))
}
}

@Test
fun `Issue 1832 - Given stdin input containing Kotlin Script resulting in a KtLintParseException when linted as Kotlin code then process the input as Kotlin Script`(
@TempDir
Expand Down
1 change: 1 addition & 0 deletions ktlint-rule-engine/api/ktlint-rule-engine.api
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public final class com/pinterest/ktlint/rule/engine/api/Code$Companion {
public final fun fromSnippetWithPath (Ljava/lang/String;Ljava/nio/file/Path;)Lcom/pinterest/ktlint/rule/engine/api/Code;
public static synthetic fun fromSnippetWithPath$default (Lcom/pinterest/ktlint/rule/engine/api/Code$Companion;Ljava/lang/String;Ljava/nio/file/Path;ILjava/lang/Object;)Lcom/pinterest/ktlint/rule/engine/api/Code;
public final fun fromStdin ()Lcom/pinterest/ktlint/rule/engine/api/Code;
public final fun fromStdin (Ljava/nio/file/Path;)Lcom/pinterest/ktlint/rule/engine/api/Code;
}

public final class com/pinterest/ktlint/rule/engine/api/EditorConfigDefaults {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@ public class Code private constructor(
) {
public fun fileNameOrStdin(): String =
if (isStdIn) {
STDIN_FILE
fileName ?: STDIN_FILE
} else {
fileName.orEmpty()
}

public fun filePathOrStdin(): String =
if (isStdIn) {
STDIN_FILE
filePath?.pathString ?: STDIN_FILE
} else {
filePath?.pathString.orEmpty()
}
Expand Down Expand Up @@ -115,6 +115,13 @@ public class Code private constructor(
* filesystem are ignored as the snippet is not associated with a file path. Use [Code.fromFile] for scanning a file while at the
* same time respecting the '.editorconfig' files on the path to the file.
*/
public fun fromStdin(): Code = fromSnippet(String(System.`in`.readBytes()))
public fun fromStdin(): Code = fromSnippetWithPath(String(System.`in`.readBytes()))

/**
* Create [Code] by reading the snippet from 'stdin'. The code snippet is associated with the given path. The actual file does not
* need to exist, neither do the contents of the actual file have to match with the content specified via 'stdin'. The
* '.editorconfig' files on the [virtualPath] are respected.
*/
public fun fromStdin(virtualPath: Path): Code = fromSnippetWithPath(String(System.`in`.readBytes()), virtualPath = virtualPath)
}
}

0 comments on commit 80c4d5d

Please sign in to comment.