Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions changelog/@unreleased/pr-862.v2.yml
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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<Node> 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)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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);
});
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 '''
<root>
</root>
'''.stripIndent(true)

when:
ConfigureJavaFormatterXml.configureFormatOnSave(node)
def newXml = xmlToString(node).strip()

then:
// language=xml
def expected = '''
<root>
<component name="FormatOnSaveOptions">
<option name="myRunOnSave" value="true"/>
<option name="myAllFileTypesSelected" value="false"/>
<option name="mySelectedFileTypes">
<set>
<option value="JAVA"/>
</set>
</option>
</component>
</root>
'''.stripIndent(true).strip()

newXml == expected
}

void 'adds Java to existing FormatOnSave block'() {
// language=xml
def node = new XmlParser().parseText '''
<root>
<component name="FormatOnSaveOptions">
<option name="myRunOnSave" value="true"/>
<option name="myAllFileTypesSelected" value="false"/>
<option name="mySelectedFileTypes">
<set>
<option value="Go"/>
</set>
</option>
</component>
</root>
'''.stripIndent(true)

when:
ConfigureJavaFormatterXml.configureFormatOnSave(node)
def newXml = xmlToString(node).strip()

then:
// language=xml
def expected = '''
<root>
<component name="FormatOnSaveOptions">
<option name="myRunOnSave" value="true"/>
<option name="myAllFileTypesSelected" value="false"/>
<option name="mySelectedFileTypes">
<set>
<option value="Go"/>
<option value="JAVA"/>
</set>
</option>
</component>
</root>
'''.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 '''
<root>
<component name="FormatOnSaveOptions">
<option name="myRunOnSave" value="true"/>
<!-- if myAllFileTypesSelected does not exist, it defaults to true -->
</component>
</root>
'''.stripIndent(true)

when:
ConfigureJavaFormatterXml.configureFormatOnSave(node)
def newXml = xmlToString(node).strip()

then:
// language=xml
def expected = '''
<root>
<component name="FormatOnSaveOptions">
<option name="myRunOnSave" value="true"/>
</component>
</root>
'''.stripIndent(true).strip()

newXml == expected
}

static String xmlToString(Node node) {
StringWriter sw = new StringWriter();
XmlNodePrinter nodePrinter = new XmlNodePrinter(new PrintWriter(sw));
Expand Down