diff --git a/ktfmt_idea_plugin/build.gradle.kts b/ktfmt_idea_plugin/build.gradle.kts
index f41c343b..c1de90eb 100644
--- a/ktfmt_idea_plugin/build.gradle.kts
+++ b/ktfmt_idea_plugin/build.gradle.kts
@@ -17,10 +17,10 @@ import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType.*
*/
plugins {
- java
- alias(libs.plugins.kotlin)
- alias(libs.plugins.intelliJPlatform)
- alias(libs.plugins.spotless)
+ java
+ alias(libs.plugins.kotlin)
+ alias(libs.plugins.intelliJPlatform)
+ alias(libs.plugins.spotless)
}
val ktfmtVersion = rootProject.file("../version.txt").readText().trim()
@@ -33,45 +33,38 @@ version = "$pluginVersion.$ktfmtVersion"
kotlin { jvmToolchain(17) }
repositories {
- mavenCentral()
- intellijPlatform {
- defaultRepositories()
- }
- mavenLocal()
+ mavenCentral()
+ intellijPlatform { defaultRepositories() }
+ mavenLocal()
}
dependencies {
- intellijPlatform {
- create(IntellijIdeaCommunity, "2022.3")
- instrumentationTools()
- pluginVerifier()
- zipSigner()
- }
-
- implementation("com.facebook", "ktfmt", ktfmtVersion)
- implementation(libs.googleJavaFormat)
+ intellijPlatform {
+ create(IntellijIdeaCommunity, "2022.3")
+ instrumentationTools()
+ pluginVerifier()
+ zipSigner()
+ }
+
+ implementation("com.facebook", "ktfmt", ktfmtVersion)
+ implementation(libs.googleJavaFormat)
}
intellijPlatform {
- pluginConfiguration.ideaVersion {
- sinceBuild = "223.7571.182" // 2022.3
- untilBuild = provider { null }
- }
+ pluginConfiguration.ideaVersion {
+ sinceBuild = "223.7571.182" // 2022.3
+ untilBuild = provider { null }
+ }
- publishing {
- token = System.getenv("JETBRAINS_MARKETPLACE_TOKEN")
- }
+ publishing { token = System.getenv("JETBRAINS_MARKETPLACE_TOKEN") }
- pluginVerification {
- ides {
- recommended()
- }
- }
+ pluginVerification { ides { recommended() } }
}
spotless { java { googleJavaFormat(libs.versions.googleJavaFormat.get()) } }
-val runIntellij242 by intellijPlatformTesting.runIde.registering {
- type = IntellijIdeaCommunity
- version = "2024.2"
-}
+val runIntellij242 by
+ intellijPlatformTesting.runIde.registering {
+ type = IntellijIdeaCommunity
+ version = "2024.2"
+ }
diff --git a/ktfmt_idea_plugin/src/main/java/com/facebook/ktfmt/intellij/InitialConfigurationStartupActivity.java b/ktfmt_idea_plugin/src/main/java/com/facebook/ktfmt/intellij/InitialConfigurationStartupActivity.java
deleted file mode 100644
index 00fe09ae..00000000
--- a/ktfmt_idea_plugin/src/main/java/com/facebook/ktfmt/intellij/InitialConfigurationStartupActivity.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2016 Google Inc. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.facebook.ktfmt.intellij;
-
-import com.intellij.notification.Notification;
-import com.intellij.notification.NotificationGroupManager;
-import com.intellij.notification.NotificationType;
-import com.intellij.openapi.actionSystem.AnAction;
-import com.intellij.openapi.actionSystem.AnActionEvent;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.startup.StartupActivity;
-import org.jetbrains.annotations.NotNull;
-
-final class InitialConfigurationStartupActivity implements StartupActivity.Background {
-
- private static final String NOTIFICATION_TITLE = "Enable ktfmt";
-
- @Override
- public void runActivity(@NotNull Project project) {
- KtfmtSettings settings = KtfmtSettings.getInstance(project);
-
- if (settings.isUninitialized()) {
- settings.setEnabled(false);
- displayNewUserNotification(project, settings);
- }
- }
-
- private void displayNewUserNotification(Project project, KtfmtSettings settings) {
- Notification notification =
- new Notification(
- NotificationGroupManager.getInstance()
- .getNotificationGroup(NOTIFICATION_TITLE)
- .getDisplayId(),
- NOTIFICATION_TITLE,
- "The ktfmt plugin is disabled by default.",
- NotificationType.INFORMATION);
-
- notification
- .addAction(
- new AnAction("Enable for This Project") {
- @Override
- public void actionPerformed(@NotNull AnActionEvent e) {
- settings.setEnabled(true);
- notification.expire();
- }
- })
- .notify(project);
- }
-}
diff --git a/ktfmt_idea_plugin/src/main/java/com/facebook/ktfmt/intellij/KtfmtConfigurable.form b/ktfmt_idea_plugin/src/main/java/com/facebook/ktfmt/intellij/KtfmtConfigurable.form
deleted file mode 100644
index e515398f..00000000
--- a/ktfmt_idea_plugin/src/main/java/com/facebook/ktfmt/intellij/KtfmtConfigurable.form
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
diff --git a/ktfmt_idea_plugin/src/main/java/com/facebook/ktfmt/intellij/KtfmtConfigurable.java b/ktfmt_idea_plugin/src/main/java/com/facebook/ktfmt/intellij/KtfmtConfigurable.java
deleted file mode 100644
index 9fd0e9ae..00000000
--- a/ktfmt_idea_plugin/src/main/java/com/facebook/ktfmt/intellij/KtfmtConfigurable.java
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Copyright 2016 Google Inc. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.facebook.ktfmt.intellij;
-
-import com.facebook.ktfmt.intellij.KtfmtSettings.EnabledState;
-import com.intellij.openapi.options.BaseConfigurable;
-import com.intellij.openapi.options.ConfigurationException;
-import com.intellij.openapi.options.SearchableConfigurable;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.ui.ComboBox;
-import com.intellij.uiDesigner.core.GridConstraints;
-import com.intellij.uiDesigner.core.GridLayoutManager;
-import com.intellij.uiDesigner.core.Spacer;
-import java.awt.Insets;
-import javax.swing.JCheckBox;
-import javax.swing.JComboBox;
-import javax.swing.JComponent;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import org.jetbrains.annotations.Nls;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-public class KtfmtConfigurable extends BaseConfigurable implements SearchableConfigurable {
-
- private final Project project;
- private JPanel panel;
- private JCheckBox enable;
- private JComboBox styleComboBox;
-
- public KtfmtConfigurable(Project project) {
- this.project = project;
- }
-
- @NotNull
- @Override
- public String getId() {
- return "ktfmt.settings";
- }
-
- @Nullable
- @Override
- public Runnable enableSearch(String option) {
- return null;
- }
-
- @Nls
- @Override
- public String getDisplayName() {
- return "ktfmt Settings";
- }
-
- @Nullable
- @Override
- public String getHelpTopic() {
- return null;
- }
-
- @Nullable
- @Override
- public JComponent createComponent() {
- return panel;
- }
-
- @Override
- public void apply() throws ConfigurationException {
- KtfmtSettings settings = KtfmtSettings.getInstance(project);
- settings.setEnabled(enable.isSelected() ? EnabledState.ENABLED : getDisabledState());
- settings.setUiFormatterStyle(((UiFormatterStyle) styleComboBox.getSelectedItem()));
- }
-
- private EnabledState getDisabledState() {
- // The default settings (inherited by new projects) are either 'enabled' or
- // 'show notification'. There's no way to default new projects to disabled. If
- // someone wants
- // that, we can add another checkbox, I suppose.
- return project.isDefault() ? EnabledState.UNKNOWN : EnabledState.DISABLED;
- }
-
- @Override
- public void reset() {
- KtfmtSettings settings = KtfmtSettings.getInstance(project);
- enable.setSelected(settings.isEnabled());
- styleComboBox.setSelectedItem(settings.getUiFormatterStyle());
- }
-
- @Override
- public boolean isModified() {
- KtfmtSettings settings = KtfmtSettings.getInstance(project);
- return enable.isSelected() != settings.isEnabled()
- || !styleComboBox.getSelectedItem().equals(settings.getUiFormatterStyle());
- }
-
- @Override
- public void disposeUIResources() {}
-
- private void createUIComponents() {
- styleComboBox = new ComboBox<>(UiFormatterStyle.values());
- }
-
- {
- // GUI initializer generated by IntelliJ IDEA GUI Designer
- // >>> IMPORTANT!! <<<
- // DO NOT EDIT OR ADD ANY CODE HERE!
- $$$setupUI$$$();
- }
-
- /**
- * Method generated by IntelliJ IDEA GUI Designer >>> IMPORTANT!! <<< DO NOT edit this method OR
- * call it in your code!
- *
- * @noinspection ALL
- */
- private void $$$setupUI$$$() {
- createUIComponents();
- panel = new JPanel();
- panel.setLayout(new GridLayoutManager(3, 2, new Insets(0, 0, 0, 0), -1, -1));
- enable = new JCheckBox();
- enable.setText("Enable ktfmt");
- panel.add(
- enable,
- new GridConstraints(
- 0,
- 0,
- 1,
- 2,
- GridConstraints.ANCHOR_WEST,
- GridConstraints.FILL_NONE,
- GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
- GridConstraints.SIZEPOLICY_FIXED,
- null,
- null,
- null,
- 0,
- false));
- final Spacer spacer1 = new Spacer();
- panel.add(
- spacer1,
- new GridConstraints(
- 2,
- 0,
- 1,
- 2,
- GridConstraints.ANCHOR_CENTER,
- GridConstraints.FILL_VERTICAL,
- 1,
- GridConstraints.SIZEPOLICY_WANT_GROW,
- null,
- null,
- null,
- 0,
- false));
- final JLabel label1 = new JLabel();
- label1.setText("Code style");
- panel.add(
- label1,
- new GridConstraints(
- 1,
- 0,
- 1,
- 1,
- GridConstraints.ANCHOR_WEST,
- GridConstraints.FILL_NONE,
- GridConstraints.SIZEPOLICY_FIXED,
- GridConstraints.SIZEPOLICY_FIXED,
- null,
- null,
- null,
- 0,
- false));
- panel.add(
- styleComboBox,
- new GridConstraints(
- 1,
- 1,
- 1,
- 1,
- GridConstraints.ANCHOR_WEST,
- GridConstraints.FILL_HORIZONTAL,
- GridConstraints.SIZEPOLICY_CAN_GROW,
- GridConstraints.SIZEPOLICY_FIXED,
- null,
- null,
- null,
- 1,
- false));
- }
-
- /**
- * @noinspection ALL
- */
- public JComponent $$$getRootComponent$$$() {
- return panel;
- }
-}
diff --git a/ktfmt_idea_plugin/src/main/java/com/facebook/ktfmt/intellij/KtfmtFormattingService.java b/ktfmt_idea_plugin/src/main/java/com/facebook/ktfmt/intellij/KtfmtFormattingService.java
deleted file mode 100644
index 58aaac7d..00000000
--- a/ktfmt_idea_plugin/src/main/java/com/facebook/ktfmt/intellij/KtfmtFormattingService.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright 2023 Google Inc. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.facebook.ktfmt.intellij;
-
-import static com.facebook.ktfmt.format.Formatter.format;
-
-import com.google.googlejavaformat.java.FormatterException;
-import com.intellij.formatting.service.AsyncDocumentFormattingService;
-import com.intellij.formatting.service.AsyncFormattingRequest;
-import com.intellij.openapi.project.Project;
-import com.intellij.psi.PsiFile;
-import java.util.EnumSet;
-import java.util.Set;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.kotlin.idea.KotlinFileType;
-
-/** Uses {@code ktfmt} to reformat code. */
-public class KtfmtFormattingService extends AsyncDocumentFormattingService {
-
- @Override
- protected FormattingTask createFormattingTask(AsyncFormattingRequest request) {
- Project project = request.getContext().getProject();
-
- UiFormatterStyle style = KtfmtSettings.getInstance(project).getUiFormatterStyle();
- return new KtfmtFormattingTask(request, style);
- }
-
- @Override
- protected @NotNull String getNotificationGroupId() {
- return Notifications.PARSING_ERROR_NOTIFICATION_GROUP;
- }
-
- @Override
- protected @NotNull String getName() {
- return "ktfmt";
- }
-
- @Override
- public @NotNull Set getFeatures() {
- return EnumSet.noneOf(Feature.class);
- }
-
- @Override
- public boolean canFormat(@NotNull PsiFile file) {
- return KotlinFileType.INSTANCE.getName().equals(file.getFileType().getName())
- && KtfmtSettings.getInstance(file.getProject()).isEnabled();
- }
-
- private static final class KtfmtFormattingTask implements FormattingTask {
- private final AsyncFormattingRequest request;
- private final UiFormatterStyle style;
-
- private KtfmtFormattingTask(AsyncFormattingRequest request, UiFormatterStyle style) {
- this.request = request;
- this.style = style;
- }
-
- @Override
- public void run() {
- try {
- String formattedText = format(style.getFormattingOptions(), request.getDocumentText());
- request.onTextReady(formattedText);
- } catch (FormatterException e) {
- request.onError(
- Notifications.PARSING_ERROR_TITLE,
- Notifications.parsingErrorMessage(request.getContext().getContainingFile().getName()));
- }
- }
-
- @Override
- public boolean isRunUnderProgress() {
- return true;
- }
-
- @Override
- public boolean cancel() {
- return false;
- }
- }
-}
diff --git a/ktfmt_idea_plugin/src/main/java/com/facebook/ktfmt/intellij/KtfmtSettings.java b/ktfmt_idea_plugin/src/main/java/com/facebook/ktfmt/intellij/KtfmtSettings.java
deleted file mode 100644
index 90909e61..00000000
--- a/ktfmt_idea_plugin/src/main/java/com/facebook/ktfmt/intellij/KtfmtSettings.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright 2016 Google Inc. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.facebook.ktfmt.intellij;
-
-import com.intellij.openapi.components.PersistentStateComponent;
-import com.intellij.openapi.components.State;
-import com.intellij.openapi.components.Storage;
-import com.intellij.openapi.project.Project;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-@State(
- name = "KtfmtSettings",
- storages = {@Storage("ktfmt.xml")})
-class KtfmtSettings implements PersistentStateComponent {
-
- private State state = new State();
-
- static KtfmtSettings getInstance(Project project) {
- return project.getService(KtfmtSettings.class);
- }
-
- @Nullable
- @Override
- public State getState() {
- return state;
- }
-
- @Override
- public void loadState(@NotNull State state) {
- this.state = state;
- }
-
- boolean isEnabled() {
- return state.enabled.equals(EnabledState.ENABLED);
- }
-
- void setEnabled(boolean enabled) {
- setEnabled(enabled ? EnabledState.ENABLED : EnabledState.DISABLED);
- }
-
- void setEnabled(EnabledState enabled) {
- state.enabled = enabled;
- }
-
- boolean isUninitialized() {
- return state.enabled.equals(EnabledState.UNKNOWN);
- }
-
- UiFormatterStyle getUiFormatterStyle() {
- return state.uiFormatterStyle;
- }
-
- void setUiFormatterStyle(UiFormatterStyle uiFormatterStyle) {
- state.uiFormatterStyle = uiFormatterStyle;
- }
-
- enum EnabledState {
- UNKNOWN,
- ENABLED,
- DISABLED;
- }
-
- static class State {
-
- private EnabledState enabled = EnabledState.UNKNOWN;
- public UiFormatterStyle uiFormatterStyle = UiFormatterStyle.META;
-
- // enabled used to be a boolean so we use bean property methods for backwards
- // compatibility
- public void setEnabled(@Nullable String enabledStr) {
- if (enabledStr == null) {
- enabled = EnabledState.UNKNOWN;
- } else if (Boolean.parseBoolean(enabledStr)) {
- enabled = EnabledState.ENABLED;
- } else {
- enabled = EnabledState.DISABLED;
- }
- }
-
- public String getEnabled() {
- switch (enabled) {
- case ENABLED:
- return "true";
- case DISABLED:
- return "false";
- default:
- return null;
- }
- }
- }
-}
diff --git a/ktfmt_idea_plugin/src/main/java/com/facebook/ktfmt/intellij/Notifications.java b/ktfmt_idea_plugin/src/main/java/com/facebook/ktfmt/intellij/Notifications.java
deleted file mode 100644
index b64db568..00000000
--- a/ktfmt_idea_plugin/src/main/java/com/facebook/ktfmt/intellij/Notifications.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (c) Meta Platforms, Inc. and affiliates.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.facebook.ktfmt.intellij;
-
-class Notifications {
-
- static final String PARSING_ERROR_NOTIFICATION_GROUP = "ktfmt parsing error";
- static final String PARSING_ERROR_TITLE = PARSING_ERROR_NOTIFICATION_GROUP;
-
- static String parsingErrorMessage(String filename) {
- return "ktfmt failed. Does " + filename + " have syntax errors?";
- }
-}
diff --git a/ktfmt_idea_plugin/src/main/java/com/facebook/ktfmt/intellij/UiFormatterStyle.java b/ktfmt_idea_plugin/src/main/java/com/facebook/ktfmt/intellij/UiFormatterStyle.java
deleted file mode 100644
index ac7ae57a..00000000
--- a/ktfmt_idea_plugin/src/main/java/com/facebook/ktfmt/intellij/UiFormatterStyle.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2016 Google Inc. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.facebook.ktfmt.intellij;
-
-import static com.facebook.ktfmt.format.Formatter.GOOGLE_FORMAT;
-import static com.facebook.ktfmt.format.Formatter.KOTLINLANG_FORMAT;
-import static com.facebook.ktfmt.format.Formatter.META_FORMAT;
-
-import com.facebook.ktfmt.format.FormattingOptions;
-
-/** Configuration options for the formatting style. */
-enum UiFormatterStyle {
- META("Meta (default)", META_FORMAT),
- GOOGLE("Google (internal)", GOOGLE_FORMAT),
- KOTLINLANG("Kotlinlang", KOTLINLANG_FORMAT);
-
- private final String description;
- private final FormattingOptions formattingOptions;
-
- UiFormatterStyle(String description, FormattingOptions formattingOptions) {
- this.description = description;
- this.formattingOptions = formattingOptions;
- }
-
- FormattingOptions getFormattingOptions() {
- return formattingOptions;
- }
-
- @Override
- public String toString() {
- return description;
- }
-}
diff --git a/ktfmt_idea_plugin/src/main/kotlin/com/facebook/ktfmt/intellij/InitialConfigurationStartupActivity.kt b/ktfmt_idea_plugin/src/main/kotlin/com/facebook/ktfmt/intellij/InitialConfigurationStartupActivity.kt
new file mode 100644
index 00000000..83212339
--- /dev/null
+++ b/ktfmt_idea_plugin/src/main/kotlin/com/facebook/ktfmt/intellij/InitialConfigurationStartupActivity.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.facebook.ktfmt.intellij
+
+import com.intellij.notification.Notification
+import com.intellij.notification.NotificationGroupManager
+import com.intellij.notification.NotificationType.INFORMATION
+import com.intellij.openapi.actionSystem.AnAction
+import com.intellij.openapi.actionSystem.AnActionEvent
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.startup.StartupActivity.Background
+
+class InitialConfigurationStartupActivity : Background {
+ override fun runActivity(project: Project) {
+ val settings = KtfmtSettings.getInstance(project)
+
+ if (settings.isUninitialized) {
+ settings.isEnabled = false
+ displayNewUserNotification(project, settings)
+ }
+ }
+
+ private fun displayNewUserNotification(project: Project, settings: KtfmtSettings) {
+ val notification =
+ Notification(
+ NotificationGroupManager.getInstance()
+ .getNotificationGroup(NOTIFICATION_TITLE)
+ .displayId,
+ NOTIFICATION_TITLE,
+ "The ktfmt plugin is disabled by default.",
+ INFORMATION,
+ )
+
+ notification
+ .addAction(
+ object : AnAction("Enable for This Project") {
+ override fun actionPerformed(e: AnActionEvent) {
+ settings.isEnabled = true
+ notification.expire()
+ }
+ }
+ )
+ .notify(project)
+ }
+
+ companion object {
+ private const val NOTIFICATION_TITLE = "Enable ktfmt"
+ }
+}
diff --git a/ktfmt_idea_plugin/src/main/kotlin/com/facebook/ktfmt/intellij/KtfmtConfigurable.kt b/ktfmt_idea_plugin/src/main/kotlin/com/facebook/ktfmt/intellij/KtfmtConfigurable.kt
new file mode 100644
index 00000000..95497e47
--- /dev/null
+++ b/ktfmt_idea_plugin/src/main/kotlin/com/facebook/ktfmt/intellij/KtfmtConfigurable.kt
@@ -0,0 +1,45 @@
+package com.facebook.ktfmt.intellij
+
+import com.facebook.ktfmt.intellij.KtfmtSettings.EnabledState.Disabled
+import com.facebook.ktfmt.intellij.KtfmtSettings.EnabledState.Enabled
+import com.intellij.openapi.options.BoundSearchableConfigurable
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.ui.DialogPanel
+import com.intellij.ui.dsl.builder.bindItem
+import com.intellij.ui.dsl.builder.bindSelected
+import com.intellij.ui.dsl.builder.panel
+import com.intellij.ui.layout.selected
+import javax.swing.JCheckBox
+
+@Suppress("DialogTitleCapitalization")
+class KtfmtConfigurable(project: Project) :
+ BoundSearchableConfigurable(
+ displayName = "ktfmt Settings",
+ _id = "com.facebook.ktfmt_idea_plugin.settings",
+ helpTopic = "ktfmt",
+ ) {
+ private val settings = KtfmtSettings.getInstance(project)
+
+ override fun createPanel(): DialogPanel = panel {
+ lateinit var enabledCheckbox: JCheckBox
+ row {
+ enabledCheckbox =
+ checkBox("Enable ktfmt")
+ .bindSelected(
+ getter = { settings.isEnabled },
+ setter = { settings.setEnabled(if (it) Enabled else Disabled) },
+ )
+ .component
+ }
+
+ row {
+ comboBox(UiFormatterStyle.entries.toList())
+ .label("Code style:")
+ .bindItem(
+ getter = { settings.uiFormatterStyle },
+ setter = { settings.uiFormatterStyle = it ?: UiFormatterStyle.Meta },
+ )
+ .enabledIf(enabledCheckbox.selected)
+ }
+ }
+}
diff --git a/ktfmt_idea_plugin/src/main/kotlin/com/facebook/ktfmt/intellij/KtfmtFormattingService.kt b/ktfmt_idea_plugin/src/main/kotlin/com/facebook/ktfmt/intellij/KtfmtFormattingService.kt
new file mode 100644
index 00000000..4e4cf643
--- /dev/null
+++ b/ktfmt_idea_plugin/src/main/kotlin/com/facebook/ktfmt/intellij/KtfmtFormattingService.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2023 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.facebook.ktfmt.intellij
+
+import com.facebook.ktfmt.format.Formatter.format
+import com.google.googlejavaformat.java.FormatterException
+import com.intellij.formatting.service.AsyncDocumentFormattingService
+import com.intellij.formatting.service.AsyncFormattingRequest
+import com.intellij.formatting.service.FormattingService.Feature
+import com.intellij.psi.PsiFile
+import org.jetbrains.kotlin.idea.KotlinFileType
+
+private const val PARSING_ERROR_NOTIFICATION_GROUP: String = "ktfmt parsing error"
+private const val PARSING_ERROR_TITLE: String = PARSING_ERROR_NOTIFICATION_GROUP
+
+/** Uses `ktfmt` to reformat code. */
+class KtfmtFormattingService : AsyncDocumentFormattingService() {
+ override fun createFormattingTask(request: AsyncFormattingRequest): FormattingTask {
+ val project = request.context.project
+ val style = KtfmtSettings.getInstance(project).uiFormatterStyle
+ return KtfmtFormattingTask(request, style)
+ }
+
+ override fun getNotificationGroupId(): String = PARSING_ERROR_NOTIFICATION_GROUP
+
+ override fun getName(): String = "ktfmt"
+
+ override fun getFeatures(): Set = emptySet()
+
+ override fun canFormat(file: PsiFile): Boolean =
+ KotlinFileType.INSTANCE.name == file.fileType.name &&
+ KtfmtSettings.getInstance(file.project).isEnabled
+
+ private class KtfmtFormattingTask(
+ private val request: AsyncFormattingRequest,
+ private val style: UiFormatterStyle,
+ ) : FormattingTask {
+ override fun run() {
+ try {
+ val formattedText = format(style.formattingOptions, request.documentText)
+ request.onTextReady(formattedText)
+ } catch (e: FormatterException) {
+ request.onError(
+ PARSING_ERROR_TITLE,
+ "ktfmt failed. Does ${request.context.containingFile.name} have syntax errors?",
+ )
+ }
+ }
+
+ override fun isRunUnderProgress(): Boolean = true
+
+ override fun cancel(): Boolean = false
+ }
+}
diff --git a/ktfmt_idea_plugin/src/main/kotlin/com/facebook/ktfmt/intellij/KtfmtSettings.kt b/ktfmt_idea_plugin/src/main/kotlin/com/facebook/ktfmt/intellij/KtfmtSettings.kt
new file mode 100644
index 00000000..f66bc63b
--- /dev/null
+++ b/ktfmt_idea_plugin/src/main/kotlin/com/facebook/ktfmt/intellij/KtfmtSettings.kt
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.facebook.ktfmt.intellij
+
+import com.facebook.ktfmt.intellij.KtfmtSettings.EnabledState.Disabled
+import com.facebook.ktfmt.intellij.KtfmtSettings.EnabledState.Enabled
+import com.facebook.ktfmt.intellij.KtfmtSettings.EnabledState.Unknown
+import com.facebook.ktfmt.intellij.UiFormatterStyle.Meta
+import com.intellij.openapi.components.PersistentStateComponent
+import com.intellij.openapi.components.Service
+import com.intellij.openapi.components.Service.Level.PROJECT
+import com.intellij.openapi.components.State
+import com.intellij.openapi.components.Storage
+import com.intellij.openapi.project.Project
+
+@Service(PROJECT)
+@State(name = "KtfmtSettings", storages = [Storage("ktfmt.xml")])
+internal class KtfmtSettings : PersistentStateComponent {
+ private var state = State()
+
+ override fun getState(): State = state
+
+ override fun loadState(state: State) {
+ this.state = state
+ }
+
+ var isEnabled: Boolean
+ get() = state.enabled == Enabled
+ set(enabled) {
+ setEnabled(if (enabled) Enabled else Disabled)
+ }
+
+ fun setEnabled(enabled: EnabledState) {
+ state.enabled = enabled
+ }
+
+ val isUninitialized: Boolean
+ get() = state.enabled == Unknown
+
+ var uiFormatterStyle: UiFormatterStyle
+ get() = state.uiFormatterStyle
+ set(uiFormatterStyle) {
+ state.uiFormatterStyle = uiFormatterStyle
+ }
+
+ internal enum class EnabledState {
+ Unknown,
+ Enabled,
+ Disabled,
+ }
+
+ internal class State {
+ @JvmField var enabled: EnabledState = Unknown
+ var uiFormatterStyle: UiFormatterStyle = Meta
+
+ // enabled used to be a boolean so we use bean property methods for backwards
+ // compatibility
+ fun setEnabled(enabledStr: String?) {
+ enabled =
+ when {
+ enabledStr == null -> Unknown
+ enabledStr.toBoolean() -> Enabled
+ else -> Disabled
+ }
+ }
+
+ fun getEnabled(): String? =
+ when (enabled) {
+ Enabled -> "true"
+ Disabled -> "false"
+ else -> null
+ }
+ }
+
+ companion object {
+ @JvmStatic
+ fun getInstance(project: Project): KtfmtSettings =
+ project.getService(KtfmtSettings::class.java)
+ }
+}
diff --git a/ktfmt_idea_plugin/src/main/kotlin/com/facebook/ktfmt/intellij/UiFormatterStyle.kt b/ktfmt_idea_plugin/src/main/kotlin/com/facebook/ktfmt/intellij/UiFormatterStyle.kt
new file mode 100644
index 00000000..13b47eca
--- /dev/null
+++ b/ktfmt_idea_plugin/src/main/kotlin/com/facebook/ktfmt/intellij/UiFormatterStyle.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.facebook.ktfmt.intellij
+
+import com.facebook.ktfmt.format.Formatter.GOOGLE_FORMAT
+import com.facebook.ktfmt.format.Formatter.KOTLINLANG_FORMAT
+import com.facebook.ktfmt.format.Formatter.META_FORMAT
+import com.facebook.ktfmt.format.FormattingOptions
+
+/** Configuration options for the formatting style. */
+internal enum class UiFormatterStyle(
+ private val description: String,
+ val formattingOptions: FormattingOptions,
+) {
+ Meta("Meta (default)", META_FORMAT),
+ Google("Google (internal)", GOOGLE_FORMAT),
+ KotlinLang("Kotlinlang", KOTLINLANG_FORMAT);
+
+ override fun toString(): String = description
+}
diff --git a/ktfmt_idea_plugin/src/main/resources/META-INF/plugin.xml b/ktfmt_idea_plugin/src/main/resources/META-INF/plugin.xml
index 7f5ed4b4..f47f163e 100644
--- a/ktfmt_idea_plugin/src/main/resources/META-INF/plugin.xml
+++ b/ktfmt_idea_plugin/src/main/resources/META-INF/plugin.xml
@@ -19,7 +19,6 @@
id="com.facebook.ktfmt_idea_plugin.settings"
displayName="ktfmt Settings"
parentId="editor"/>
-