diff --git a/server/src/main/kotlin/org/javacs/kt/Configuration.kt b/server/src/main/kotlin/org/javacs/kt/Configuration.kt index ad3db4bb..13774c38 100644 --- a/server/src/main/kotlin/org/javacs/kt/Configuration.kt +++ b/server/src/main/kotlin/org/javacs/kt/Configuration.kt @@ -57,6 +57,18 @@ data class InlayHintsConfiguration( var chainedHints: Boolean = false ) +data class KtfmtConfiguration( + var style: String = "google", + var indent: Int = 4, + var maxWidth: Int = 100, + var continuationIndent: Int = 8, + var removeUnusedImports: Boolean = true, +) + +data class FormattingConfiguration( + var formatter: String = "ktfmt", + var ktfmt: KtfmtConfiguration = KtfmtConfiguration() +) fun getStoragePath(params: InitializeParams): Path? { params.initializationOptions?.let { initializationOptions -> @@ -94,5 +106,6 @@ public data class Configuration( val scripts: ScriptsConfiguration = ScriptsConfiguration(), val indexing: IndexingConfiguration = IndexingConfiguration(), val externalSources: ExternalSourcesConfiguration = ExternalSourcesConfiguration(), - val inlayHints: InlayHintsConfiguration = InlayHintsConfiguration() + val inlayHints: InlayHintsConfiguration = InlayHintsConfiguration(), + val formatting: FormattingConfiguration = FormattingConfiguration(), ) diff --git a/server/src/main/kotlin/org/javacs/kt/KotlinTextDocumentService.kt b/server/src/main/kotlin/org/javacs/kt/KotlinTextDocumentService.kt index cbacca58..2ec1e522 100644 --- a/server/src/main/kotlin/org/javacs/kt/KotlinTextDocumentService.kt +++ b/server/src/main/kotlin/org/javacs/kt/KotlinTextDocumentService.kt @@ -8,7 +8,7 @@ import org.javacs.kt.codeaction.codeActions import org.javacs.kt.completion.completions import org.javacs.kt.definition.goToDefinition import org.javacs.kt.diagnostic.convertDiagnostic -import org.javacs.kt.formatting.formatKotlinCode +import org.javacs.kt.formatting.FormattingService import org.javacs.kt.hover.hoverAt import org.javacs.kt.position.offset import org.javacs.kt.position.extractRange @@ -45,6 +45,7 @@ class KotlinTextDocumentService( ) : TextDocumentService, Closeable { private lateinit var client: LanguageClient private val async = AsyncExecutor() + private val formattingService = FormattingService(config.formatting) var debounceLint = Debouncer(Duration.ofMillis(config.diagnostics.debounceTime)) val lintTodo = mutableSetOf() @@ -139,7 +140,7 @@ class KotlinTextDocumentService( val code = extractRange(params.textDocument.content, params.range) listOf(TextEdit( params.range, - formatKotlinCode(code, params.options) + formattingService.formatKotlinCode(code, params.options) )) } @@ -215,7 +216,7 @@ class KotlinTextDocumentService( LOG.info("Formatting {}", describeURI(params.textDocument.uri)) listOf(TextEdit( Range(Position(0, 0), position(code, code.length)), - formatKotlinCode(code, params.options) + formattingService.formatKotlinCode(code, params.options) )) } diff --git a/server/src/main/kotlin/org/javacs/kt/KotlinWorkspaceService.kt b/server/src/main/kotlin/org/javacs/kt/KotlinWorkspaceService.kt index 6b89473e..82ec771b 100644 --- a/server/src/main/kotlin/org/javacs/kt/KotlinWorkspaceService.kt +++ b/server/src/main/kotlin/org/javacs/kt/KotlinWorkspaceService.kt @@ -103,6 +103,22 @@ class KotlinWorkspaceService( } } + // Update options for formatting + get("formatting")?.asJsonObject?.apply { + val formatting = config.formatting + get("formatter")?.asString?.let { + formatting.formatter = it + } + get("ktfmt")?.asJsonObject?.apply { + val ktfmt = formatting.ktfmt + get("style")?.asString?.let { ktfmt.style = it } + get("indent")?.asInt?.let { ktfmt.indent = it } + get("maxWidth")?.asInt?.let { ktfmt.maxWidth = it } + get("continuationIndent")?.asInt?.let { ktfmt.continuationIndent = it } + get("removeUnusedImports")?.asBoolean?.let { ktfmt.removeUnusedImports = it } + } + } + // Update options for inlay hints get("inlayHints")?.asJsonObject?.apply { val inlayHints = config.inlayHints diff --git a/server/src/main/kotlin/org/javacs/kt/formatting/Formatter.kt b/server/src/main/kotlin/org/javacs/kt/formatting/Formatter.kt index d0a5a536..901942e0 100644 --- a/server/src/main/kotlin/org/javacs/kt/formatting/Formatter.kt +++ b/server/src/main/kotlin/org/javacs/kt/formatting/Formatter.kt @@ -1,14 +1,8 @@ package org.javacs.kt.formatting -import com.facebook.ktfmt.format.Formatter -import com.facebook.ktfmt.format.FormattingOptions as KtfmtOptions -import org.eclipse.lsp4j.FormattingOptions +import org.eclipse.lsp4j.FormattingOptions as LspFromattingOptions + +interface Formatter { + fun format(code: String, options: LspFromattingOptions): String +} -fun formatKotlinCode( - code: String, - options: FormattingOptions = FormattingOptions(4, true) -): String = Formatter.format(KtfmtOptions( - style = KtfmtOptions.Style.GOOGLE, - blockIndent = options.tabSize, - continuationIndent = 2 * options.tabSize -), code) diff --git a/server/src/main/kotlin/org/javacs/kt/formatting/FormattingService.kt b/server/src/main/kotlin/org/javacs/kt/formatting/FormattingService.kt new file mode 100644 index 00000000..97cc16bc --- /dev/null +++ b/server/src/main/kotlin/org/javacs/kt/formatting/FormattingService.kt @@ -0,0 +1,21 @@ +package org.javacs.kt.formatting + +import org.javacs.kt.Configuration +import org.javacs.kt.FormattingConfiguration +import org.eclipse.lsp4j.FormattingOptions as LspFromattingOptions + +private const val DEFAULT_INDENT = 4 + +class FormattingService(private val config: FormattingConfiguration) { + + private val formatter: Formatter get() = when (config.formatter) { + "ktfmt" -> KtfmtFormatter(config.ktfmt) + "none" -> NopFormatter + else -> KtfmtFormatter(config.ktfmt) + } + + fun formatKotlinCode( + code: String, + options: LspFromattingOptions = LspFromattingOptions(DEFAULT_INDENT, true) + ): String = this.formatter.format(code, options) +} diff --git a/server/src/main/kotlin/org/javacs/kt/formatting/KtfmtFormatter.kt b/server/src/main/kotlin/org/javacs/kt/formatting/KtfmtFormatter.kt new file mode 100644 index 00000000..5b4012fc --- /dev/null +++ b/server/src/main/kotlin/org/javacs/kt/formatting/KtfmtFormatter.kt @@ -0,0 +1,28 @@ +package org.javacs.kt.formatting + +import org.javacs.kt.KtfmtConfiguration +import com.facebook.ktfmt.format.Formatter as Ktfmt +import com.facebook.ktfmt.format.FormattingOptions as KtfmtOptions +import org.eclipse.lsp4j.FormattingOptions as LspFormattingOptions + +class KtfmtFormatter(private val config: KtfmtConfiguration) : Formatter { + override fun format( + code: String, + options: LspFormattingOptions, + ): String { + val style = when (config.style) { + "google" -> KtfmtOptions.Style.GOOGLE + "facebook" -> KtfmtOptions.Style.FACEBOOK + "dropbox" -> KtfmtOptions.Style.DROPBOX + else -> KtfmtOptions.Style.GOOGLE + } + return Ktfmt.format(KtfmtOptions( + style = style, + maxWidth = config.maxWidth, + blockIndent = options.tabSize.takeUnless { it == 0 } ?: config.indent, + continuationIndent = config.continuationIndent, + removeUnusedImports = config.removeUnusedImports, + ), code) + } +} + diff --git a/server/src/main/kotlin/org/javacs/kt/formatting/NopFormatter.kt b/server/src/main/kotlin/org/javacs/kt/formatting/NopFormatter.kt new file mode 100644 index 00000000..bd72856b --- /dev/null +++ b/server/src/main/kotlin/org/javacs/kt/formatting/NopFormatter.kt @@ -0,0 +1,8 @@ +package org.javacs.kt.formatting + +import org.eclipse.lsp4j.FormattingOptions as LspFormattingOptions + +object NopFormatter : Formatter { + override fun format(code: String, options: LspFormattingOptions): String = code +} +