1 /*
2  * Copyright (c) Meta Platforms, Inc. and affiliates.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.facebook.ktfmt.intellij
18 
19 import com.facebook.ktfmt.format.Formatter.format
20 import com.facebook.ktfmt.format.FormattingOptions
21 import com.google.googlejavaformat.java.FormatterException
22 import com.intellij.formatting.service.AsyncDocumentFormattingService
23 import com.intellij.formatting.service.AsyncFormattingRequest
24 import com.intellij.formatting.service.FormattingService.Feature
25 import com.intellij.psi.PsiFile
26 import org.jetbrains.kotlin.idea.KotlinFileType
27 
28 private const val PARSING_ERROR_NOTIFICATION_GROUP: String = "ktfmt parsing error"
29 private const val PARSING_ERROR_TITLE: String = PARSING_ERROR_NOTIFICATION_GROUP
30 
31 /** Uses `ktfmt` to reformat code. */
32 class KtfmtFormattingService : AsyncDocumentFormattingService() {
createFormattingTasknull33   override fun createFormattingTask(request: AsyncFormattingRequest): FormattingTask {
34     val project = request.context.project
35     val settings = KtfmtSettings.getInstance(project)
36     val style = settings.uiFormatterStyle
37     val formattingOptions =
38         if (style == UiFormatterStyle.Custom) {
39           settings.customFormattingOptions
40         } else {
41           UiFormatterStyle.getStandardFormattingOptions(style)
42         }
43     return KtfmtFormattingTask(request, formattingOptions)
44   }
45 
getNotificationGroupIdnull46   override fun getNotificationGroupId(): String = PARSING_ERROR_NOTIFICATION_GROUP
47 
48   override fun getName(): String = "ktfmt"
49 
50   override fun getFeatures(): Set<Feature> = emptySet()
51 
52   override fun canFormat(file: PsiFile): Boolean =
53       KotlinFileType.INSTANCE.name == file.fileType.name &&
54           KtfmtSettings.getInstance(file.project).isEnabled
55 
56   private class KtfmtFormattingTask(
57       private val request: AsyncFormattingRequest,
58       private val formattingOptions: FormattingOptions,
59   ) : FormattingTask {
60     override fun run() {
61       try {
62         val formattedText = format(formattingOptions, request.documentText)
63         request.onTextReady(formattedText)
64       } catch (e: FormatterException) {
65         request.onError(
66             PARSING_ERROR_TITLE,
67             "ktfmt failed. Does ${request.context.containingFile.name} have syntax errors?",
68         )
69       }
70     }
71 
72     override fun isRunUnderProgress(): Boolean = true
73 
74     override fun cancel(): Boolean = false
75   }
76 }
77