Skip to content

Commit 79637d3

Browse files
authored
Merge pull request #42 from block/mehdi.idea-plugin-config
Add configuration for using a formatting script in the idea-plugin
2 parents 78d468e + 1c6050e commit 79637d3

File tree

4 files changed

+84
-12
lines changed

4 files changed

+84
-12
lines changed

README.md

+25-3
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,22 @@
33
[![release](https://img.shields.io/maven-central/v/xyz.block.kotlin-formatter/kotlin-formatter?label=release&color=blue)](https://central.sonatype.com/namespace/xyz.block.kotlin-formatter)
44
[![main](https://github.com/block/kotlin-formatter/actions/workflows/push.yml/badge.svg)](https://github.com/block/kotlin-formatter/actions/workflows/push.yml)
55

6-
**A command-line tool for formatting Kotlin source code files**, implemented as a wrapper around [ktfmt](https://github.com/facebook/ktfmt/tree/main).
6+
This project provides:
7+
- **A command-line tool for formatting Kotlin source code files**, implemented as a wrapper around [ktfmt](https://github.com/facebook/ktfmt/tree/main).
8+
- **An IntelliJ idea plugin** for formatting Kotlin source code files.
79

810
It can be used to automate code formatting, ensuring a clean and consistent codebase, while integrating seamlessly into development workflows.
911

10-
The tool can:
12+
The CLI tool can:
1113

1214
- **Format files and directories**: Apply consistent formatting to files, directories, or standard input.
1315
- **Integrate with Git workflows**:
1416
- **Pre-commit**: Format staged files before committing.
1517
- **Pre-push**: Check committed files before pushing.
1618

17-
## Usage
19+
The plugin can format Kotlin files on save, or on the format action.
20+
21+
## CLI Usage
1822

1923
```bash
2024
kotlin-format [OPTIONS] [FILES...]
@@ -70,3 +74,21 @@ A fat JAR of the CLI is available on [Maven Central](https://repo1.maven.org/mav
7074
```bash
7175
java -jar path/to/kotlin-formatter-$version-all.jar [OPTIONS] [FILES...]
7276
```
77+
78+
## Idea Plugin Usage
79+
80+
A properties file can be used to configure the plugin for each project. The properties file should be named `kotlin-formatter.properties` and placed in the `.idea` of the project. The following properties are supported:
81+
82+
- `kotlin-formatter.enabled`: Enable or disable the plugin, disabled by default.
83+
- `kotlin-formatter.script-path`: Path to the Kotlin Formatter script. The `kotlin-format` library in this project is used if this is not specified.
84+
85+
Example:
86+
```properties
87+
kotlin-formatter.enabled=true
88+
kotlin-formatter.script-path=bin/kotlin-format
89+
```
90+
91+
Changes to these config require an IDE restart to take effect.
92+
93+
To enable formatting of files on save, navigate to "Settings" > "Tools" > Actions on Save", activate the "Reformat code" checkbox, and ensure that the "Kotlin" file type is selected.
94+
Make sure "Optimize imports" is NOT enabled for the "Kotlin" file type.

idea-plugin/src/main/kotlin/xyz/block/kotlinformatter/idea/FormatConfigurationService.kt

+16-6
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,33 @@ class FormatConfigurationService(private val project: Project) {
1212

1313
// This is calculated once and on demand.
1414
// Changes to the config file will require a restart.
15-
val formattingEnabled by lazy {
15+
private val config: Properties by lazy {
1616
val configFile = project.getFile(CONFIG_FILE_PATH)
17-
val enabled = configFile?.let { file ->
18-
val properties = Properties()
17+
val properties = Properties()
18+
configFile?.let { file ->
1919
InputStreamReader(file.inputStream).use {
2020
properties.load(it)
21-
properties.getProperty(ENABLED_PROPERTY_NAME)?.toBoolean() == true
2221
}
23-
} ?: false
22+
}
23+
properties
24+
}
2425

26+
val formattingEnabled: Boolean by lazy {
27+
val enabled = config.getProperty(ENABLED_PROPERTY_NAME)?.toBoolean() ?: false
2528
logger.info("Formatting enabled: $enabled")
2629
enabled
2730
}
2831

32+
val scriptPath: String? by lazy {
33+
val path = config.getProperty(SCRIPT_PATH_PROPERTY_NAME)
34+
logger.info("Formatting script: $path")
35+
path
36+
}
37+
2938
companion object {
30-
private const val CONFIG_FILE_PATH: String = ".idea/kotlin-formater.properties"
39+
private const val CONFIG_FILE_PATH: String = ".idea/kotlin-formatter.properties"
3140
private const val ENABLED_PROPERTY_NAME: String = "kotlin-formatter.enabled"
41+
private const val SCRIPT_PATH_PROPERTY_NAME: String = "kotlin-formatter.script-path"
3242
private val logger = Logger.getInstance(FormatConfigurationService::class.java.name)
3343
}
3444
}

idea-plugin/src/main/kotlin/xyz/block/kotlinformatter/idea/FormatOnSaveListener.kt

+4-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ import java.util.concurrent.ConcurrentHashMap
1919
/**
2020
* A listener that formats a document when it is saved.
2121
*/
22-
class FormatOnSaveListener(private val project: Project, private val formatter: AsyncDocumentFormattingService) :
22+
class FormatOnSaveListener(
23+
private val project: Project,
24+
private val formatter: AsyncDocumentFormattingService
25+
) :
2326
FileDocumentManagerListener {
2427

2528
/**

idea-plugin/src/main/kotlin/xyz/block/kotlinformatter/idea/KotlinReformatService.kt

+39-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import com.intellij.openapi.diagnostic.Logger
88
import com.intellij.psi.PsiFile
99
import xyz.block.kotlinformatter.Ktfmt
1010
import xyz.block.kotlinformatter.idea.KotlinReformatService.Companion.FORMATTING_IGNORE_FILE
11+
import java.io.File
12+
import kotlin.text.Charsets.UTF_8
1113

1214
/**
1315
* A service that overrides the default IntelliJ formatting behavior for Kotlin files.
@@ -34,12 +36,12 @@ class KotlinReformatService : AsyncDocumentFormattingService() {
3436
return !isFormattingIgnored(file)
3537
}
3638

37-
override fun createFormattingTask(request: AsyncFormattingRequest): FormattingTask? {
39+
override fun createFormattingTask(request: AsyncFormattingRequest): FormattingTask {
3840
return object : FormattingTask {
3941
override fun run() {
4042
ApplicationManager.getApplication().executeOnPooledThread {
4143
try {
42-
val formattedCode = Ktfmt().format(request.documentText)
44+
val formattedCode = format(request)
4345
request.onTextReady(formattedCode)
4446
} catch (e: Exception) {
4547
// If an error occurs, notify IntelliJ
@@ -62,6 +64,41 @@ class KotlinReformatService : AsyncDocumentFormattingService() {
6264
return "Reformat Kotlin Files"
6365
}
6466

67+
private fun format(request: AsyncFormattingRequest): String {
68+
val file = request.context.psiElement.containingFile
69+
val scriptPath = file.project.getService(FormatConfigurationService::class.java).scriptPath
70+
return if (scriptPath != null) {
71+
72+
val process = ProcessBuilder(scriptPath, "--set-exit-if-changed", "-")
73+
.directory(file.project.basePath?.let { File(it) })
74+
.start()
75+
76+
// Stream file content to the process's input
77+
file.virtualFile.inputStream.use { inputStream ->
78+
process.outputStream.use { outputStream -> inputStream.copyTo(outputStream) }
79+
}
80+
81+
val formattedContent = process.inputStream.bufferedReader(UTF_8).use { it.readText() }
82+
83+
// Wait for the process to complete
84+
val exitCode = process.waitFor()
85+
LOG.info("Process exited with code: $exitCode")
86+
return when (exitCode) {
87+
3 -> formattedContent
88+
0 -> {
89+
LOG.info("Nothing to format")
90+
request.documentText
91+
}
92+
else -> {
93+
LOG.error("Formatting failed with exit code $exitCode")
94+
request.documentText
95+
}
96+
}
97+
} else {
98+
Ktfmt().format(request.documentText)
99+
}
100+
}
101+
65102
/**
66103
* Determines whether formatting should be ignored for the given module based on [FORMATTING_IGNORE_FILE].
67104
*

0 commit comments

Comments
 (0)