Skip to content

Commit

Permalink
POC of google-java-format support
Browse files Browse the repository at this point in the history
Signed-off-by: Shi Chen <[email protected]>
  • Loading branch information
CsCherrYY committed Apr 14, 2023
1 parent 934f22e commit 6ad7232
Show file tree
Hide file tree
Showing 9 changed files with 166 additions and 10 deletions.
2 changes: 1 addition & 1 deletion launch/jdt.ls.remote.server.launch
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17"/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog"/>
<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Djava.import.generatesMetadataFilesAtProjectRoot=false"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Djava.import.generatesMetadataFilesAtProjectRoot=false --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"/>
<stringAttribute key="pde.version" value="3.3"/>
<stringAttribute key="product" value="org.eclipse.sdk.ide"/>
<setAttribute key="selected_features"/>
Expand Down
2 changes: 1 addition & 1 deletion launch/jdt.ls.socket-stream.launch
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17"/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog"/>
<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Djava.import.generatesMetadataFilesAtProjectRoot=false"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Djava.import.generatesMetadataFilesAtProjectRoot=false --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"/>
<stringAttribute key="pde.version" value="3.3"/>
<stringAttribute key="product" value="org.eclipse.sdk.ide"/>
<setAttribute key="selected_features"/>
Expand Down
1 change: 1 addition & 0 deletions org.eclipse.jdt.ls.core/.classpath
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry exported="true" kind="lib" path="lib/jsoup-1.14.2.jar"/>
<classpathentry exported="true" kind="lib" path="lib/remark-1.2.0.jar"/>
<classpathentry exported="true" kind="lib" path="lib/google-java-format-1.13.0.jar"/>
<classpathentry kind="src" path="src/"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>
1 change: 1 addition & 0 deletions org.eclipse.jdt.ls.core/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ Export-Package: org.eclipse.jdt.ls.core.contentassist;x-friends:="org.eclipse.jd
org.eclipse.lsp4j.legacy.typeHierarchy;x-friends:="org.eclipse.jdt.ls.tests"
Bundle-ClassPath: lib/jsoup-1.14.2.jar,
lib/remark-1.2.0.jar,
lib/google-java-format-1.13.0.jar,
.
Bundle-Vendor: %Bundle-Vendor
Automatic-Module-Name: org.eclipse.jdt.ls.core
1 change: 1 addition & 0 deletions org.eclipse.jdt.ls.core/build.properties
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ bin.includes = META-INF/,\
plugin.xml,\
lib/jsoup-1.14.2.jar,\
lib/remark-1.2.0.jar,\
lib/google-java-format-1.13.0.jar,\
lifecycle-mapping-metadata.xml,\
plugin.properties,\
gradle/checksums/checksums.json,\
Expand Down
5 changes: 5 additions & 0 deletions org.eclipse.jdt.ls.core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@
<artifactId>jsoup</artifactId>
<version>1.14.2</version>
</artifactItem>
<artifactItem>
<groupId>com.google.googlejavaformat</groupId>
<artifactId>google-java-format</artifactId>
<version>1.13.0</version>
</artifactItem>
</artifactItems>
</configuration>
</plugin>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package com.google.googlejavaformat.java;

import com.google.common.base.Preconditions;
import com.google.common.collect.Range;
import com.google.googlejavaformat.java.SnippetFormatter.SnippetKind;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.formatter.CodeFormatter;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.Region;
import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.text.edits.ReplaceEdit;
import org.eclipse.text.edits.TextEdit;

/** Runs the Google Java formatter on the given code. */
public class GoogleJavaFormatter extends CodeFormatter {

private static final int INDENTATION_SIZE = 2;

@Override
public TextEdit format(
int kind, String source, int offset, int length, int indentationLevel, String lineSeparator) {
IRegion[] regions = new IRegion[] {new Region(offset, length)};
return formatInternal(kind, source, regions, indentationLevel);
}

@Override
public TextEdit format(
int kind, String source, IRegion[] regions, int indentationLevel, String lineSeparator) {
return formatInternal(kind, source, regions, indentationLevel);
}

@Override
public String createIndentationString(int indentationLevel) {
Preconditions.checkArgument(
indentationLevel >= 0,
"Indentation level cannot be less than zero. Given: %s",
indentationLevel);
int spaces = indentationLevel * INDENTATION_SIZE;
StringBuilder buf = new StringBuilder(spaces);
for (int i = 0; i < spaces; i++) {
buf.append(' ');
}
return buf.toString();
}

/** Runs the Google Java formatter on the given source, with only the given ranges specified. */
private TextEdit formatInternal(int kind, String source, IRegion[] regions, int initialIndent) {
try {
boolean includeComments =
(kind & CodeFormatter.F_INCLUDE_COMMENTS) == CodeFormatter.F_INCLUDE_COMMENTS;
kind &= ~CodeFormatter.F_INCLUDE_COMMENTS;
SnippetKind snippetKind;
switch (kind) {
case ASTParser.K_EXPRESSION:
snippetKind = SnippetKind.EXPRESSION;
break;
case ASTParser.K_STATEMENTS:
snippetKind = SnippetKind.STATEMENTS;
break;
case ASTParser.K_CLASS_BODY_DECLARATIONS:
snippetKind = SnippetKind.CLASS_BODY_DECLARATIONS;
break;
case ASTParser.K_COMPILATION_UNIT:
snippetKind = SnippetKind.COMPILATION_UNIT;
break;
default:
throw new IllegalArgumentException(String.format("Unknown snippet kind: %d", kind));
}
List<Replacement> replacements =
new SnippetFormatter()
.format(
snippetKind, source, rangesFromRegions(regions), initialIndent, includeComments);
if (idempotent(source, regions, replacements)) {
// Do not create edits if there's no diff.
return null;
}
// Convert replacements to text edits.
return editFromReplacements(replacements);
} catch (IllegalArgumentException | FormatterException exception) {
// Do not format on errors.
return null;
}
}

private List<Range<Integer>> rangesFromRegions(IRegion[] regions) {
List<Range<Integer>> ranges = new ArrayList<>();
for (IRegion region : regions) {
ranges.add(Range.closedOpen(region.getOffset(), region.getOffset() + region.getLength()));
}
return ranges;
}

/** @return {@code true} if input and output texts are equal, else {@code false}. */
private boolean idempotent(String source, IRegion[] regions, List<Replacement> replacements) {
// This implementation only checks for single replacement.
if (replacements.size() == 1) {
Replacement replacement = replacements.get(0);
String output = replacement.getReplacementString();
// Entire source case: input = output, nothing changed.
if (output.equals(source)) {
return true;
}
// Single region and single replacement case: if they are equal, nothing changed.
if (regions.length == 1) {
Range<Integer> range = replacement.getReplaceRange();
String snippet = source.substring(range.lowerEndpoint(), range.upperEndpoint());
if (output.equals(snippet)) {
return true;
}
}
}
return false;
}

private TextEdit editFromReplacements(List<Replacement> replacements) {
// Split the replacements that cross line boundaries.
TextEdit edit = new MultiTextEdit();
for (Replacement replacement : replacements) {
Range<Integer> replaceRange = replacement.getReplaceRange();
edit.addChild(
new ReplaceEdit(
replaceRange.lowerEndpoint(),
replaceRange.upperEndpoint() - replaceRange.lowerEndpoint(),
replacement.getReplacementString()));
}
return edit;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin;
import org.eclipse.jdt.ls.core.internal.preferences.FormatterPreferences;
import org.eclipse.jdt.ls.core.internal.preferences.PreferenceManager;
import org.eclipse.jdt.ls.core.internal.preferences.Preferences.FormatterScheme;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocument;
Expand All @@ -57,6 +58,8 @@
import org.eclipse.text.edits.ReplaceEdit;
import org.eclipse.text.edits.TextEdit;

import com.google.googlejavaformat.java.GoogleJavaFormatter;

/**
* @author IBM Corporation (Markus Keller)
*/
Expand Down Expand Up @@ -109,18 +112,29 @@ private List<org.eclipse.lsp4j.TextEdit> format(ICompilationUnit cu, IDocument d
return Collections.emptyList();
}

CodeFormatter formatter = ToolFactory.createCodeFormatter(getOptions(options, cu));
CodeFormatter formatter;
if (this.preferenceManager.getPreferences().getFormatterScheme().equals(FormatterScheme.google)) {
formatter = new GoogleJavaFormatter();
} else {
formatter = ToolFactory.createCodeFormatter(getOptions(options, cu));
}

String lineDelimiter = TextUtilities.getDefaultLineDelimiter(document);
String sourceToFormat = document.get();
int kind = getFormattingKind(cu, includeComments);
TextEdit format = formatter.format(kind, sourceToFormat, region.getOffset(), region.getLength(), 0, lineDelimiter);
if (format == null || format.getChildren().length == 0 || monitor.isCanceled()) {
// nothing to return
return Collections.<org.eclipse.lsp4j.TextEdit>emptyList();

try {
TextEdit format = formatter.format(kind, sourceToFormat, region.getOffset(), region.getLength(), 0, lineDelimiter);
if (format == null || format.getChildren().length == 0 || monitor.isCanceled()) {
// nothing to return
return Collections.<org.eclipse.lsp4j.TextEdit>emptyList();
}
MultiTextEdit flatEdit = TextEditUtil.flatten(format);
return convertEdits(flatEdit.getChildren(), document);
} catch (Throwable e) {
JavaLanguageServerPlugin.logException(e);
}
MultiTextEdit flatEdit = TextEditUtil.flatten(format);
return convertEdits(flatEdit.getChildren(), document);
return Collections.<org.eclipse.lsp4j.TextEdit>emptyList();
}

private int getFormattingKind(ICompilationUnit cu, boolean includeComments) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -729,7 +729,7 @@ static FeatureStatus fromString(String value, FeatureStatus defaultStatus) {
}

public static enum FormatterScheme {
eclipse;
eclipse, google;

static FormatterScheme fromString(String value, FormatterScheme defaultValue) {
if (value != null) {
Expand Down Expand Up @@ -1690,6 +1690,10 @@ public Map<String, String> getFormatterSettings() {
return this.formatterSettings;
}

public FormatterScheme getFormatterScheme() {
return this.formatterScheme;
}

public String getSettingsUrl() {
return settingsUrl;
}
Expand Down

0 comments on commit 6ad7232

Please sign in to comment.