diff --git a/changelog/@unreleased/pr-862.v2.yml b/changelog/@unreleased/pr-862.v2.yml new file mode 100644 index 000000000..cebae4f26 --- /dev/null +++ b/changelog/@unreleased/pr-862.v2.yml @@ -0,0 +1,6 @@ +type: fix +fix: + description: Stop using the Save Actions plugin (broken in IntelliJ 2023.1) and + use native format on save (requires IntelliJ >=2021.2) + links: + - https://github.com/palantir/palantir-java-format/pull/862 diff --git a/gradle-palantir-java-format/src/main/groovy/com/palantir/javaformat/gradle/ConfigureJavaFormatterXml.groovy b/gradle-palantir-java-format/src/main/groovy/com/palantir/javaformat/gradle/ConfigureJavaFormatterXml.groovy index e4cc96614..12e1261d6 100644 --- a/gradle-palantir-java-format/src/main/groovy/com/palantir/javaformat/gradle/ConfigureJavaFormatterXml.groovy +++ b/gradle-palantir-java-format/src/main/groovy/com/palantir/javaformat/gradle/ConfigureJavaFormatterXml.groovy @@ -35,12 +35,47 @@ class ConfigureJavaFormatterXml { matchOrCreateChild(externalDependencies, 'plugin', [id: 'palantir-java-format']) } + static void configureFormatOnSave(Node rootNode) { + def formatOnSaveOptions = matchOrCreateChild(rootNode, 'component', [name: 'FormatOnSaveOptions']) + + + def myRunOnSave = matchOrCreateChild(formatOnSaveOptions, 'option', [name: 'myRunOnSave']) + + def myRunOnSaveAlreadySet = Optional.ofNullable(myRunOnSave.attribute('value')) + .map(Boolean::parseBoolean) + .orElse(false) + + myRunOnSave.attributes().put('value', 'true') + + def myAllFileTypesSelectedAlreadySet = matchChild(formatOnSaveOptions, 'option', [name: 'myAllFileTypesSelected']) + .map { Boolean.parseBoolean(it.attribute('value')) } + .orElse(true) + + if (myRunOnSaveAlreadySet && myAllFileTypesSelectedAlreadySet) { + // If the user has already configured IntelliJ to format all file types and turned on formatting on save, + // we leave the configuration as is as it will format java code, and we don't want to disable formatting + // for other file types + return + } + + // Otherwise we setup intellij to not format all files... + matchOrCreateChild(formatOnSaveOptions, 'option', [name: 'myAllFileTypesSelected']).attributes().put('value', 'false') + + // ...but ensure java is formatted + def mySelectedFileTypes = matchOrCreateChild(formatOnSaveOptions, 'option', [name: 'mySelectedFileTypes']) + def set = matchOrCreateChild(mySelectedFileTypes, 'set') + matchOrCreateChild(set, 'option', [value: 'JAVA']) + } + private static Node matchOrCreateChild(Node base, String name, Map attributes = [:], Map defaults = [:]) { - def child = base[name].find { it.attributes().entrySet().containsAll(attributes.entrySet()) } - if (child) { - return child + matchChild(base, name, attributes).orElseGet { + base.appendNode(name, attributes + defaults) } + } + + private static Optional matchChild(Node base, String name, Map attributes = [:]) { + def child = base[name].find { it.attributes().entrySet().containsAll(attributes.entrySet()) } - return base.appendNode(name, attributes + defaults) + return Optional.ofNullable(child) } } diff --git a/gradle-palantir-java-format/src/main/groovy/com/palantir/javaformat/gradle/PalantirJavaFormatIdeaPlugin.java b/gradle-palantir-java-format/src/main/groovy/com/palantir/javaformat/gradle/PalantirJavaFormatIdeaPlugin.java index e1908ae2f..dba0a4145 100644 --- a/gradle-palantir-java-format/src/main/groovy/com/palantir/javaformat/gradle/PalantirJavaFormatIdeaPlugin.java +++ b/gradle-palantir-java-format/src/main/groovy/com/palantir/javaformat/gradle/PalantirJavaFormatIdeaPlugin.java @@ -66,6 +66,10 @@ private static void configureLegacyIdea(Project project, Configuration implConfi ConfigureJavaFormatterXml.configureJavaFormat(xmlProvider.asNode(), uris); ConfigureJavaFormatterXml.configureExternalDependencies(xmlProvider.asNode()); }); + + ideaModel.getWorkspace().getIws().withXml(xmlProvider -> { + ConfigureJavaFormatterXml.configureFormatOnSave(xmlProvider.asNode()); + }); } private static void configureIntelliJImport(Project project, Configuration implConfiguration) { @@ -86,10 +90,17 @@ private static void configureIntelliJImport(Project project, Configuration implC createOrUpdateIdeaXmlFile( project.file(".idea/externalDependencies.xml"), node -> ConfigureJavaFormatterXml.configureExternalDependencies(node)); + createOrUpdateIdeaXmlFile( + project.file(".idea/workspace.xml"), node -> ConfigureJavaFormatterXml.configureFormatOnSave(node)); + + // Still configure legacy idea if using intellij import updateIdeaXmlFileIfExists(project.file(project.getName() + ".ipr"), node -> { ConfigureJavaFormatterXml.configureJavaFormat(node, uris); ConfigureJavaFormatterXml.configureExternalDependencies(node); }); + updateIdeaXmlFileIfExists(project.file(project.getName() + ".iws"), node -> { + ConfigureJavaFormatterXml.configureFormatOnSave(node); + }); }); } diff --git a/gradle-palantir-java-format/src/test/groovy/com/palantir/javaformat/gradle/ConfigureJavaFormatterXmlTest.groovy b/gradle-palantir-java-format/src/test/groovy/com/palantir/javaformat/gradle/ConfigureJavaFormatterXmlTest.groovy index 4037b946e..041cf664c 100644 --- a/gradle-palantir-java-format/src/test/groovy/com/palantir/javaformat/gradle/ConfigureJavaFormatterXmlTest.groovy +++ b/gradle-palantir-java-format/src/test/groovy/com/palantir/javaformat/gradle/ConfigureJavaFormatterXmlTest.groovy @@ -104,6 +104,104 @@ class ConfigureJavaFormatterXmlTest extends Specification { xmlToString(node) == EXPECTED } + void 'adds FormatOnSave block where none exists'() { + // language=xml + def node = new XmlParser().parseText ''' + + + '''.stripIndent(true) + + when: + ConfigureJavaFormatterXml.configureFormatOnSave(node) + def newXml = xmlToString(node).strip() + + then: + // language=xml + def expected = ''' + + + + + + '''.stripIndent(true).strip() + + newXml == expected + } + + void 'adds Java to existing FormatOnSave block'() { + // language=xml + def node = new XmlParser().parseText ''' + + + + + + '''.stripIndent(true) + + when: + ConfigureJavaFormatterXml.configureFormatOnSave(node) + def newXml = xmlToString(node).strip() + + then: + // language=xml + def expected = ''' + + + + + + '''.stripIndent(true).strip() + + newXml == expected + } + + void 'if all file types are already formatted on save, dont change anything'() { + // language=xml + def node = new XmlParser().parseText ''' + + + + + '''.stripIndent(true) + + when: + ConfigureJavaFormatterXml.configureFormatOnSave(node) + def newXml = xmlToString(node).strip() + + then: + // language=xml + def expected = ''' + + + + + '''.stripIndent(true).strip() + + newXml == expected + } + static String xmlToString(Node node) { StringWriter sw = new StringWriter(); XmlNodePrinter nodePrinter = new XmlNodePrinter(new PrintWriter(sw));