inpu
* Also trim leading and trailing blank lines, and move the trailing `}` to its own line.
*/
private static ImmutableList deindentPreCodeBlocks(List input) {
+ // TODO: b/323389829 - De-indent {@snippet ...} blocks, too.
ImmutableList.Builder output = ImmutableList.builder();
for (PeekingIterator tokens = peekingIterator(input.iterator()); tokens.hasNext(); ) {
if (tokens.peek().getType() != PRE_OPEN_TAG) {
@@ -528,6 +548,7 @@ private static boolean hasMultipleNewlines(String s) {
private static final Pattern BLOCKQUOTE_OPEN_PATTERN = openTagPattern("blockquote");
private static final Pattern BLOCKQUOTE_CLOSE_PATTERN = closeTagPattern("blockquote");
private static final Pattern BR_PATTERN = openTagPattern("br");
+ private static final Pattern SNIPPET_TAG_OPEN_PATTERN = compile("^[{]@snippet\\b");
private static final Pattern INLINE_TAG_OPEN_PATTERN = compile("^[{]@\\w*");
/*
* We exclude < so that we don't swallow following HTML tags. This lets us fix up "foo" (~400
diff --git a/core/src/main/java/com/google/googlejavaformat/java/javadoc/JavadocWriter.java b/core/src/main/java/com/google/googlejavaformat/java/javadoc/JavadocWriter.java
index 0361415a1..8a4100e45 100644
--- a/core/src/main/java/com/google/googlejavaformat/java/javadoc/JavadocWriter.java
+++ b/core/src/main/java/com/google/googlejavaformat/java/javadoc/JavadocWriter.java
@@ -123,6 +123,38 @@ void writeFooterJavadocTagStart(Token token) {
continuingFooterTag = true;
}
+ void writeSnippetBegin(Token token) {
+ requestBlankLine();
+ writeToken(token);
+ /*
+ * We don't request a newline here because we should have at least a colon following on this
+ * line, and we may have attributes after that.
+ *
+ * (If we find it convenient, we could instead consume the entire rest of the line as part of
+ * the same token as `{@snippet` itself. But we already would never split the rest of the line
+ * across lines (because we preserve whitespace), so that might not accomplish anything. Plus,
+ * we'd probably want to be careful not to swallow an expectedly early closing `}`.)
+ */
+ }
+
+ void writeSnippetEnd(Token token) {
+ /*
+ * We don't request a newline here because we have preserved all newlines that existed in the
+ * input. TODO: b/323389829 - Improve upon that. Specifically:
+ *
+ * - If there is not yet a newline, we should add one.
+ *
+ * - If there are multiple newlines, we should probably collapse them.
+ *
+ * - If the closing brace isn't indented as we'd want (as in the link below, in which the whole
+ * @apiNote isn't indented), we should indent it.
+ *
+ * https://github.com/openjdk/jdk/blob/1ebf2cf639300728ffc024784f5dc1704317b0b3/src/java.base/share/classes/java/util/Collections.java#L5993-L6006
+ */
+ writeToken(token);
+ requestBlankLine();
+ }
+
void writeListOpen(Token token) {
requestBlankLine();
diff --git a/core/src/main/java/com/google/googlejavaformat/java/javadoc/Token.java b/core/src/main/java/com/google/googlejavaformat/java/javadoc/Token.java
index d617824b0..f74996060 100644
--- a/core/src/main/java/com/google/googlejavaformat/java/javadoc/Token.java
+++ b/core/src/main/java/com/google/googlejavaformat/java/javadoc/Token.java
@@ -41,6 +41,10 @@ enum Type {
END_JAVADOC,
/** The {@code @foo} that begins a block Javadoc tag like {@code @throws}. */
FOOTER_JAVADOC_TAG_START,
+ /** The opening {@code {@snippet} of a code snippet. */
+ SNIPPET_BEGIN,
+ /** The closing {@code }} of a code snippet. */
+ SNIPPET_END,
LIST_OPEN_TAG,
LIST_CLOSE_TAG,
LIST_ITEM_OPEN_TAG,
diff --git a/core/src/main/scripts/google-java-format.el b/core/src/main/scripts/google-java-format.el
index 5df8a1396..1bb3ffdc2 100644
--- a/core/src/main/scripts/google-java-format.el
+++ b/core/src/main/scripts/google-java-format.el
@@ -2,8 +2,6 @@
;;
;; Copyright 2015 Google, Inc. All Rights Reserved.
;;
-;; Package-Requires: ((emacs "24"))
-;;
;; 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
@@ -17,6 +15,8 @@
;; limitations under the License.
;; Keywords: tools, Java
+;; Version: 0.1.0
+;; Package-Requires: ((emacs "24"))
;;; Commentary:
@@ -109,5 +109,4 @@ there is no region, then formats the current line."
(defalias 'google-java-format 'google-java-format-region)
(provide 'google-java-format)
-
;;; google-java-format.el ends here
diff --git a/core/src/test/java/com/google/googlejavaformat/java/DiagnosticTest.java b/core/src/test/java/com/google/googlejavaformat/java/DiagnosticTest.java
index fc966fac3..e05a37264 100644
--- a/core/src/test/java/com/google/googlejavaformat/java/DiagnosticTest.java
+++ b/core/src/test/java/com/google/googlejavaformat/java/DiagnosticTest.java
@@ -79,7 +79,7 @@ public void parseError() throws Exception {
int result = main.format(path.toString());
assertThat(stdout.toString()).isEmpty();
- assertThat(stderr.toString()).contains("InvalidSyntax.java:2:29: error: expected");
+ assertThat(stderr.toString()).contains("InvalidSyntax.java:2:28: error: expected");
assertThat(result).isEqualTo(1);
}
@@ -119,7 +119,7 @@ public void oneFileParseError() throws Exception {
int result = main.format(pathOne.toString(), pathTwo.toString());
assertThat(stdout.toString()).isEqualTo(two);
- assertThat(stderr.toString()).contains("One.java:1:13: error: reached end of file");
+ assertThat(stderr.toString()).contains("One.java:1:12: error: reached end of file");
assertThat(result).isEqualTo(1);
}
@@ -141,7 +141,7 @@ public void oneFileParseErrorReplace() throws Exception {
int result = main.format("-i", pathOne.toString(), pathTwo.toString());
assertThat(stdout.toString()).isEmpty();
- assertThat(stderr.toString()).contains("One.java:1:14: error: class, interface");
+ assertThat(stderr.toString()).contains("One.java:1:13: error: class, interface");
assertThat(result).isEqualTo(1);
// don't edit files with parse errors
assertThat(Files.readAllLines(pathOne, UTF_8)).containsExactly("class One {}}");
@@ -164,7 +164,7 @@ public void parseError2() throws FormatterException, IOException, UsageException
int exitCode = main.format(args);
assertThat(exitCode).isEqualTo(1);
- assertThat(err.toString()).contains("A.java:2:6: error: ';' expected");
+ assertThat(err.toString()).contains("A.java:2:5: error: ';' expected");
}
@Test
@@ -179,7 +179,7 @@ public void parseErrorStdin() throws FormatterException, IOException, UsageExcep
int exitCode = main.format(args);
assertThat(exitCode).isEqualTo(1);
- assertThat(err.toString()).contains(":2:6: error: ';' expected");
+ assertThat(err.toString()).contains(":2:5: error: ';' expected");
}
@Test
@@ -198,7 +198,7 @@ public void lexError2() throws FormatterException, IOException, UsageException {
int exitCode = main.format(args);
assertThat(exitCode).isEqualTo(1);
- assertThat(err.toString()).contains("A.java:2:5: error: unclosed character literal");
+ assertThat(err.toString()).contains("A.java:2:4: error: unclosed character literal");
}
@Test
@@ -212,6 +212,6 @@ public void lexErrorStdin() throws FormatterException, IOException, UsageExcepti
int exitCode = main.format(args);
assertThat(exitCode).isEqualTo(1);
- assertThat(err.toString()).contains(":2:5: error: unclosed character literal");
+ assertThat(err.toString()).contains(":2:4: error: unclosed character literal");
}
}
diff --git a/core/src/test/java/com/google/googlejavaformat/java/JavadocFormattingTest.java b/core/src/test/java/com/google/googlejavaformat/java/JavadocFormattingTest.java
index 6849c01f2..aab8ec5d4 100644
--- a/core/src/test/java/com/google/googlejavaformat/java/JavadocFormattingTest.java
+++ b/core/src/test/java/com/google/googlejavaformat/java/JavadocFormattingTest.java
@@ -906,6 +906,48 @@ public void unicodeCharacterCountArguableBug() {
doFormatTest(input, expected);
}
+ @Test
+ public void blankLinesAroundSnippetAndNoMangling() {
+ String[] input = {
+ "/**", //
+ " * hello world",
+ " * {@snippet :",
+ " * public class Foo {",
+ " * private String s;",
+ " * }",
+ " * }",
+ " * hello again",
+ " */",
+ "class Test {}",
+ };
+ String[] expected = {
+ "/**", //
+ " * hello world",
+ " *",
+ " * {@snippet :",
+ " * public class Foo {",
+ " * private String s;",
+ " * }",
+ " * }",
+ " *",
+ " * hello again",
+ " */",
+ "class Test {}",
+ };
+ doFormatTest(input, expected);
+ }
+
+ @Test
+ public void notASnippetUnlessOuterTag() {
+ String[] input = {
+ "/** I would like to tell you about the {@code {@snippet ...}} tag. */", "class Test {}",
+ };
+ String[] expected = {
+ "/** I would like to tell you about the {@code {@snippet ...}} tag. */", "class Test {}",
+ };
+ doFormatTest(input, expected);
+ }
+
@Test
public void blankLineBeforeParams() {
String[] input = {
diff --git a/core/src/test/java/com/google/googlejavaformat/java/MainTest.java b/core/src/test/java/com/google/googlejavaformat/java/MainTest.java
index 42e12d860..2d9364082 100644
--- a/core/src/test/java/com/google/googlejavaformat/java/MainTest.java
+++ b/core/src/test/java/com/google/googlejavaformat/java/MainTest.java
@@ -307,7 +307,7 @@ public void importRemoveErrorParseError() throws Exception {
new PrintWriter(err, true),
new ByteArrayInputStream(joiner.join(input).getBytes(UTF_8)));
assertThat(main.format("-")).isEqualTo(1);
- assertThat(err.toString()).contains(":4:3: error: class, interface");
+ assertThat(err.toString()).contains(":4:2: error: class, interface");
} finally {
Locale.setDefault(backupLocale);
@@ -508,7 +508,7 @@ public void assumeFilename_error() throws Exception {
new PrintWriter(err, true),
new ByteArrayInputStream(joiner.join(input).getBytes(UTF_8)));
assertThat(main.format("--assume-filename=Foo.java", "-")).isEqualTo(1);
- assertThat(err.toString()).contains("Foo.java:1:15: error: class, interface");
+ assertThat(err.toString()).contains("Foo.java:1:14: error: class, interface");
}
@Test
@@ -635,4 +635,59 @@ public void reorderModifiersOptionTest() throws Exception {
.formatSource(source))
.isEqualTo(source);
}
+
+ @Test
+ public void syntaxError() throws Exception {
+ Path path = testFolder.newFile("Test.java").toPath();
+ String[] input = {
+ "class Test {", //
+ " void f(int package) {",
+ " int",
+ " }",
+ "}",
+ "",
+ };
+ String source = joiner.join(input);
+ Files.writeString(path, source, UTF_8);
+ StringWriter out = new StringWriter();
+ StringWriter err = new StringWriter();
+ Main main = new Main(new PrintWriter(out, true), new PrintWriter(err, true), System.in);
+ int errorCode = main.format(path.toAbsolutePath().toString());
+ assertWithMessage("Error Code").that(errorCode).isEqualTo(1);
+ String[] expected = {
+ path + ":2:13: error: expected",
+ " void f(int package) {",
+ " ^",
+ path + ":3:5: error: not a statement",
+ " int",
+ " ^",
+ path + ":3:8: error: ';' expected",
+ " int",
+ " ^",
+ "",
+ };
+ assertThat(err.toString()).isEqualTo(joiner.join(expected));
+ }
+
+ @Test
+ public void syntaxErrorBeginning() throws Exception {
+ Path path = testFolder.newFile("Test.java").toPath();
+ String[] input = {
+ "error", //
+ };
+ String source = joiner.join(input);
+ Files.writeString(path, source, UTF_8);
+ StringWriter out = new StringWriter();
+ StringWriter err = new StringWriter();
+ Main main = new Main(new PrintWriter(out, true), new PrintWriter(err, true), System.in);
+ int errorCode = main.format(path.toAbsolutePath().toString());
+ assertWithMessage("Error Code").that(errorCode).isEqualTo(1);
+ String[] expected = {
+ path + ":1:1: error: reached end of file while parsing", //
+ "error",
+ "^",
+ "",
+ };
+ assertThat(err.toString()).isEqualTo(joiner.join(expected));
+ }
}
diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/I1153.input b/core/src/test/resources/com/google/googlejavaformat/java/testdata/I1153.input
new file mode 100644
index 000000000..e2b27dde1
--- /dev/null
+++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/I1153.input
@@ -0,0 +1,15 @@
+class I1153 {
+ void f() {
+ //// (1) one
+ int one;
+
+ //// (2) two
+ int two;
+
+ //// (2.1) if we need to collect data using multiple different collectors, e.g. taxonomy and
+ //// ranges, or even two taxonomy facets that use different Category List Field, we can
+ //// use MultiCollectorManager, e.g.:
+ // TODO: This should be (2.1) two point one
+ int twoPointOne;
+ }
+}
diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/I1153.output b/core/src/test/resources/com/google/googlejavaformat/java/testdata/I1153.output
new file mode 100644
index 000000000..e2b27dde1
--- /dev/null
+++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/I1153.output
@@ -0,0 +1,15 @@
+class I1153 {
+ void f() {
+ //// (1) one
+ int one;
+
+ //// (2) two
+ int two;
+
+ //// (2.1) if we need to collect data using multiple different collectors, e.g. taxonomy and
+ //// ranges, or even two taxonomy facets that use different Category List Field, we can
+ //// use MultiCollectorManager, e.g.:
+ // TODO: This should be (2.1) two point one
+ int twoPointOne;
+ }
+}
diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/LegacySwitchComment.input b/core/src/test/resources/com/google/googlejavaformat/java/testdata/LegacySwitchComment.input
new file mode 100644
index 000000000..07ce2f4d2
--- /dev/null
+++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/LegacySwitchComment.input
@@ -0,0 +1,17 @@
+class T {
+ int test(String v) {
+ switch (v) {
+ // this is a line comment about "zero"
+ case "zero":
+ return 0;
+ case "one":
+ // this is a line comment about "one"
+ return 1;
+ // this is a line comment about "two"
+ case "two":
+ return 2;
+ default:
+ return -1;
+ }
+ }
+}
\ No newline at end of file
diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/LegacySwitchComment.output b/core/src/test/resources/com/google/googlejavaformat/java/testdata/LegacySwitchComment.output
new file mode 100644
index 000000000..70a0b6bea
--- /dev/null
+++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/LegacySwitchComment.output
@@ -0,0 +1,17 @@
+class T {
+ int test(String v) {
+ switch (v) {
+ // this is a line comment about "zero"
+ case "zero":
+ return 0;
+ case "one":
+ // this is a line comment about "one"
+ return 1;
+ // this is a line comment about "two"
+ case "two":
+ return 2;
+ default:
+ return -1;
+ }
+ }
+}
diff --git a/eclipse_plugin/META-INF/MANIFEST.MF b/eclipse_plugin/META-INF/MANIFEST.MF
index 913245393..e81bc8ec0 100644
--- a/eclipse_plugin/META-INF/MANIFEST.MF
+++ b/eclipse_plugin/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2
Bundle-Name: google-java-format
Bundle-SymbolicName: google-java-format-eclipse-plugin;singleton:=true
Bundle-Vendor: Google
-Bundle-Version: 1.13.0
+Bundle-Version: 1.24.0
Bundle-RequiredExecutionEnvironment: JavaSE-11
Require-Bundle: org.eclipse.jdt.core;bundle-version="3.10.0",
org.eclipse.jface,
diff --git a/eclipse_plugin/pom.xml b/eclipse_plugin/pom.xml
index b2c6e368a..71ad8eacd 100644
--- a/eclipse_plugin/pom.xml
+++ b/eclipse_plugin/pom.xml
@@ -22,7 +22,7 @@
com.google.googlejavaformat
google-java-format-eclipse-plugin
eclipse-plugin
- 1.13.0
+ 1.24.0
Google Java Format Plugin for Eclipse 4.5+
diff --git a/idea_plugin/.gitignore b/idea_plugin/.gitignore
index 16bc65a53..a5e690ca2 100644
--- a/idea_plugin/.gitignore
+++ b/idea_plugin/.gitignore
@@ -2,4 +2,5 @@ build
.gradle
gradle
gradlew
-gradlew.bat
\ No newline at end of file
+gradlew.bat
+.intellijPlatform
\ No newline at end of file
diff --git a/idea_plugin/build.gradle.kts b/idea_plugin/build.gradle.kts
index 0ba5032dc..c7d1d4ba1 100644
--- a/idea_plugin/build.gradle.kts
+++ b/idea_plugin/build.gradle.kts
@@ -1,3 +1,4 @@
+import org.jetbrains.intellij.platform.gradle.TestFrameworkType
/*
* Copyright 2017 Google Inc. All Rights Reserved.
*
@@ -15,56 +16,76 @@
*/
// https://github.com/JetBrains/intellij-platform-gradle-plugin/releases
-plugins { id("org.jetbrains.intellij") version "1.17.3" }
-
-apply(plugin = "org.jetbrains.intellij")
+plugins {
+ id("org.jetbrains.intellij.platform") version "2.0.1"
+}
-apply(plugin = "java")
+repositories {
+ mavenCentral()
-repositories { mavenCentral() }
+ intellijPlatform {
+ defaultRepositories()
+ }
+}
// https://github.com/google/google-java-format/releases
-val googleJavaFormatVersion = "1.22.0"
+val googleJavaFormatVersion = "1.23.0"
java {
- sourceCompatibility = JavaVersion.VERSION_11
- targetCompatibility = JavaVersion.VERSION_11
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
}
-intellij {
- pluginName.set("google-java-format")
- plugins.set(listOf("java"))
- version.set("2021.3")
-}
-
-tasks {
- patchPluginXml {
- version.set("${googleJavaFormatVersion}.0")
- sinceBuild.set("213")
- untilBuild.set("")
+intellijPlatform {
+ pluginConfiguration {
+ name = "google-java-format"
+ version = "${googleJavaFormatVersion}.0"
+ ideaVersion {
+ sinceBuild = "223"
+ untilBuild = provider { null }
+ }
}
- publishPlugin {
+ publishing {
val jetbrainsPluginRepoToken: String by project
token.set(jetbrainsPluginRepoToken)
}
+}
+var gjfRequiredJvmArgs =
+ listOf(
+ "--add-exports", "jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED",
+ "--add-exports", "jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED",
+ "--add-exports", "jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED",
+ "--add-exports", "jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED",
+ "--add-exports", "jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED",
+ "--add-exports", "jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED",
+ )
+
+tasks {
+ runIde {
+ jvmArgumentProviders += CommandLineArgumentProvider {
+ gjfRequiredJvmArgs
+ }
+ }
+}
+
+tasks {
withType().configureEach {
- jvmArgs(
- "--add-exports", "jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED",
- "--add-exports", "jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED",
- "--add-exports", "jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED",
- "--add-exports", "jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED",
- "--add-exports", "jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED",
- "--add-exports", "jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED",
- )
+ jvmArgs(gjfRequiredJvmArgs)
}
}
dependencies {
+ intellijPlatform {
+ intellijIdeaCommunity("2022.3")
+ bundledPlugin("com.intellij.java")
+ instrumentationTools()
+ testFramework(TestFrameworkType.Plugin.Java)
+ }
implementation("com.google.googlejavaformat:google-java-format:${googleJavaFormatVersion}")
// https://mvnrepository.com/artifact/junit/junit
testImplementation("junit:junit:4.13.2")
// https://mvnrepository.com/artifact/com.google.truth/truth
- testImplementation("com.google.truth:truth:1.4.2")
+ testImplementation("com.google.truth:truth:1.4.4")
}
diff --git a/idea_plugin/src/main/java/com/google/googlejavaformat/intellij/InitialConfigurationStartupActivity.java b/idea_plugin/src/main/java/com/google/googlejavaformat/intellij/InitialConfigurationStartupActivity.java
index 940def655..95e13d325 100644
--- a/idea_plugin/src/main/java/com/google/googlejavaformat/intellij/InitialConfigurationStartupActivity.java
+++ b/idea_plugin/src/main/java/com/google/googlejavaformat/intellij/InitialConfigurationStartupActivity.java
@@ -27,8 +27,6 @@
final class InitialConfigurationStartupActivity implements StartupActivity.Background {
private static final String NOTIFICATION_TITLE = "Enable google-java-format";
- private static final NotificationGroup NOTIFICATION_GROUP =
- NotificationGroupManager.getInstance().getNotificationGroup(NOTIFICATION_TITLE);
@Override
public void runActivity(@NotNull Project project) {
@@ -43,9 +41,11 @@ public void runActivity(@NotNull Project project) {
}
private void displayNewUserNotification(Project project, GoogleJavaFormatSettings settings) {
+ NotificationGroupManager groupManager = NotificationGroupManager.getInstance();
+ NotificationGroup group = groupManager.getNotificationGroup(NOTIFICATION_TITLE);
Notification notification =
new Notification(
- NOTIFICATION_GROUP.getDisplayId(),
+ group.getDisplayId(),
NOTIFICATION_TITLE,
"The google-java-format plugin is disabled by default. "
+ "Enable for this project.",
diff --git a/idea_plugin/src/main/resources/META-INF/plugin.xml b/idea_plugin/src/main/resources/META-INF/plugin.xml
index 378c2529c..8d7574539 100644
--- a/idea_plugin/src/main/resources/META-INF/plugin.xml
+++ b/idea_plugin/src/main/resources/META-INF/plugin.xml
@@ -35,6 +35,10 @@
]]>
+ 1.23.0.0
+ Updated to use google-java-format 1.23.0.
+ Fix crashes in IntelliJ 2024.2 (Thanks, @nrayburn-tech!)
+ Updated to the latest IntelliJ build system (Thanks, @mmaeller!)
1.22.0.0
Updated to use google-java-format 1.22.0.
1.21.0.0
diff --git a/pom.xml b/pom.xml
index 96e613a0a..32a3558a7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -23,7 +23,7 @@
com.google.googlejavaformat
google-java-format-parent
pom
- HEAD-SNAPSHOT
+ 1.24.0
core