diff --git a/launch/jdt.ls.socket-stream.launch b/launch/jdt.ls.socket-stream.launch
index 362e437aec..15dcc1418c 100644
--- a/launch/jdt.ls.socket-stream.launch
+++ b/launch/jdt.ls.socket-stream.launch
@@ -40,12 +40,12 @@
-
+
-
+
diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/JavaClientConnection.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/JavaClientConnection.java
index 22bff38b8f..6be5dbf446 100644
--- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/JavaClientConnection.java
+++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/JavaClientConnection.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2016-2018 Red Hat Inc. and others.
+ * Copyright (c) 2016-2020 Red Hat Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
@@ -24,6 +24,7 @@
import org.eclipse.lsp4j.ApplyWorkspaceEditParams;
import org.eclipse.lsp4j.ApplyWorkspaceEditResponse;
import org.eclipse.lsp4j.Command;
+import org.eclipse.lsp4j.ConfigurationParams;
import org.eclipse.lsp4j.ExecuteCommandParams;
import org.eclipse.lsp4j.MessageActionItem;
import org.eclipse.lsp4j.MessageParams;
@@ -222,6 +223,13 @@ public void semanticHighlighting(SemanticHighlightingParams params) {
client.semanticHighlighting(params);
}
+ /**
+ * @see {@link LanguageClient#configuration(ConfigurationParams)}
+ */
+ public List configuration(ConfigurationParams configurationParams) {
+ return this.client.configuration(configurationParams).join();
+ }
+
public void disconnect() {
if (logHandler != null) {
logHandler.uninstall();
diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/codemanipulation/GenerateGetterSetterOperation.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/codemanipulation/GenerateGetterSetterOperation.java
index 31565a0779..b289e1cd4b 100644
--- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/codemanipulation/GenerateGetterSetterOperation.java
+++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/codemanipulation/GenerateGetterSetterOperation.java
@@ -15,6 +15,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
@@ -158,7 +159,8 @@ private void insertMethod(IField field, ListRewrite rewrite, AccessorKind kind)
stub = GetterSetterUtil.getSetterStub(field, name, generateComments, flags);
}
- String formattedStub = CodeFormatterUtil.format(CodeFormatter.K_CLASS_BODY_DECLARATIONS, stub, 0, delimiter, type.getJavaProject().getOptions(true));
+ Map options = type.getCompilationUnit() != null ? type.getCompilationUnit().getOptions(true) : type.getJavaProject().getOptions(true);
+ String formattedStub = CodeFormatterUtil.format(CodeFormatter.K_CLASS_BODY_DECLARATIONS, stub, 0, delimiter, options);
MethodDeclaration declaration = (MethodDeclaration) rewrite.getASTRewrite().createStringPlaceholder(formattedStub, ASTNode.METHOD_DECLARATION);
rewrite.insertLast(declaration, null);
}
diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/contentassist/AnonymousTypeCompletionProposal.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/contentassist/AnonymousTypeCompletionProposal.java
index cc8fbc2cab..b478009658 100644
--- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/contentassist/AnonymousTypeCompletionProposal.java
+++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/contentassist/AnonymousTypeCompletionProposal.java
@@ -99,9 +99,8 @@ public String updateReplacementString(IDocument document, int offset, ImportRewr
buf.append(newBody);
// use the code formatter
String lineDelim = TextUtilities.getDefaultLineDelimiter(document);
- final IJavaProject project = fCompilationUnit.getJavaProject();
IRegion lineInfo = document.getLineInformationOfOffset(fReplacementOffset);
- Map options = project != null ? project.getOptions(true) : JavaCore.getOptions();
+ Map options = fCompilationUnit.getOptions(true);
String replacementString = CodeFormatterUtil.format(CodeFormatter.K_EXPRESSION, buf.toString(), 0, lineDelim, options);
int lineEndOffset = lineInfo.getOffset() + lineInfo.getLength();
int p = offset;
diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/contentassist/OverrideCompletionProposal.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/contentassist/OverrideCompletionProposal.java
index 4d85fcfcd9..3257b5eada 100644
--- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/contentassist/OverrideCompletionProposal.java
+++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/contentassist/OverrideCompletionProposal.java
@@ -147,7 +147,7 @@ public String updateReplacementString(IDocument document, int offset, ImportRewr
ITrackedNodePosition position= rewrite.track(stub);
try {
- Map options = fJavaProject.getOptions(true);
+ Map options = fCompilationUnit.getOptions(true);
rewrite.rewriteAST(recoveredDocument, options).apply(recoveredDocument);
diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corext/refactoring/code/ExtractMethodRefactoring.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corext/refactoring/code/ExtractMethodRefactoring.java
index eea50becfb..e497c0a8e5 100644
--- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corext/refactoring/code/ExtractMethodRefactoring.java
+++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corext/refactoring/code/ExtractMethodRefactoring.java
@@ -600,7 +600,7 @@ public Change createChange(IProgressMonitor pm) throws CoreException {
result.addTextEditGroup(new TextEditGroup(RefactoringCoreMessages.ExtractMethodRefactoring_organize_imports, new TextEdit[] { edit }));
}
try {
- Map formatter = this.fFormatterOptions == null ? fCUnit.getJavaProject().getOptions(true) : this.fFormatterOptions;
+ Map formatter = this.fFormatterOptions == null ? fCUnit.getOptions(true) : this.fFormatterOptions;
IDocument document = new Document(fCUnit.getSource());
root.addChild(fRewriter.rewriteAST(document, formatter));
} catch (JavaModelException e) {
diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corext/refactoring/delegates/DelegateCreator.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corext/refactoring/delegates/DelegateCreator.java
index 660582313b..045877949d 100644
--- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corext/refactoring/delegates/DelegateCreator.java
+++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corext/refactoring/delegates/DelegateCreator.java
@@ -361,7 +361,7 @@ private void createJavadoc() throws JavaModelException {
public void createEdit() throws JavaModelException {
try {
IDocument document= new Document(fDelegateRewrite.getCu().getBuffer().getContents());
- TextEdit edit= fDelegateRewrite.getASTRewrite().rewriteAST(document, fDelegateRewrite.getCu().getJavaProject().getOptions(true));
+ TextEdit edit= fDelegateRewrite.getASTRewrite().rewriteAST(document, fDelegateRewrite.getCu().getOptions(true));
edit.apply(document, TextEdit.UPDATE_REGIONS);
int tabWidth = CodeFormatterUtil.getTabWidth(fOriginalRewrite.getCu().getJavaProject());
diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corext/refactoring/reorg/DeleteChangeCreator.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corext/refactoring/reorg/DeleteChangeCreator.java
index 594ad1149f..9b18bfeb08 100644
--- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corext/refactoring/reorg/DeleteChangeCreator.java
+++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corext/refactoring/reorg/DeleteChangeCreator.java
@@ -133,7 +133,7 @@ private static Change createDeleteChange(ICompilationUnit cu, List
private static TextChange addTextEditFromRewrite(TextChangeManager manager, ICompilationUnit cu, ASTRewrite rewrite) throws CoreException {
try {
ITextFileBuffer buffer= RefactoringFileBuffers.acquire(cu);
- TextEdit resultingEdits= rewrite.rewriteAST(buffer.getDocument(), cu.getJavaProject().getOptions(true));
+ TextEdit resultingEdits= rewrite.rewriteAST(buffer.getDocument(), cu.getOptions(true));
TextChange textChange= manager.get(cu);
if (textChange instanceof TextFileChange) {
TextFileChange tfc= (TextFileChange) textChange;
diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corrections/proposals/AbstractMethodCorrectionProposal.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corrections/proposals/AbstractMethodCorrectionProposal.java
index 41463f4843..617d246cc9 100644
--- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corrections/proposals/AbstractMethodCorrectionProposal.java
+++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corrections/proposals/AbstractMethodCorrectionProposal.java
@@ -154,7 +154,7 @@ private MethodDeclaration getStub(ASTRewrite rewrite, ASTNode targetTypeDecl) th
if (!isAbstractMethod && !isVoid) {
ReturnStatement returnStatement= ast.newReturnStatement();
returnStatement.setExpression(ASTNodeFactory.newDefaultExpression(ast, returnType, 0));
- bodyStatement= ASTNodes.asFormattedString(returnStatement, 0, String.valueOf('\n'), getCompilationUnit().getJavaProject().getOptions(true));
+ bodyStatement= ASTNodes.asFormattedString(returnStatement, 0, String.valueOf('\n'), getCompilationUnit().getOptions(true));
}
}
diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corrections/proposals/ConstructorFromSuperclassProposal.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corrections/proposals/ConstructorFromSuperclassProposal.java
index 2c703ba2f8..2f23682401 100644
--- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corrections/proposals/ConstructorFromSuperclassProposal.java
+++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corrections/proposals/ConstructorFromSuperclassProposal.java
@@ -163,7 +163,7 @@ private MethodDeclaration createNewMethodDeclaration(AST ast, IMethodBinding bin
}
}
- String bodyStatement = (invocation == null) ? "" : ASTNodes.asFormattedString(invocation, 0, String.valueOf('\n'), getCompilationUnit().getJavaProject().getOptions(true)); //$NON-NLS-1$
+ String bodyStatement = (invocation == null) ? "" : ASTNodes.asFormattedString(invocation, 0, String.valueOf('\n'), getCompilationUnit().getOptions(true)); //$NON-NLS-1$
String placeHolder= CodeGeneration.getMethodBodyContent(getCompilationUnit(), name, name, true, bodyStatement, String.valueOf('\n'));
if (placeHolder != null) {
ASTNode todoNode= rewrite.createStringPlaceholder(placeHolder, ASTNode.RETURN_STATEMENT);
diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corrections/proposals/ModifierChangeCorrectionProposal.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corrections/proposals/ModifierChangeCorrectionProposal.java
index 304045e268..9d344d2b74 100644
--- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corrections/proposals/ModifierChangeCorrectionProposal.java
+++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corrections/proposals/ModifierChangeCorrectionProposal.java
@@ -113,7 +113,7 @@ protected ASTRewrite getRewrite() throws CoreException {
if (expression != null) {
ReturnStatement returnStatement = ast.newReturnStatement();
returnStatement.setExpression(expression);
- bodyStatement = ASTNodes.asFormattedString(returnStatement, 0, delimiter, unit.getJavaProject().getOptions(true));
+ bodyStatement = ASTNodes.asFormattedString(returnStatement, 0, delimiter, unit.getOptions(true));
}
}
String placeHolder = CodeGeneration.getMethodBodyContent(unit, methodBinding.getDeclaringClass().getName(), methodBinding.getName(), false, bodyStatement, delimiter);
diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/CodeActionHandler.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/CodeActionHandler.java
index cc3b49e96c..0a757a8803 100644
--- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/CodeActionHandler.java
+++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/CodeActionHandler.java
@@ -16,7 +16,9 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
@@ -26,7 +28,9 @@
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaModelMarker;
+import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.dom.CompilationUnit;
+import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants;
import org.eclipse.jdt.core.manipulation.CoreASTProvider;
import org.eclipse.jdt.internal.ui.text.correction.IProblemLocationCore;
import org.eclipse.jdt.internal.ui.text.correction.ProblemLocationCore;
@@ -40,6 +44,7 @@
import org.eclipse.jdt.ls.core.internal.corrections.RefactorProcessor;
import org.eclipse.jdt.ls.core.internal.corrections.proposals.ChangeCorrectionProposal;
import org.eclipse.jdt.ls.core.internal.preferences.PreferenceManager;
+import org.eclipse.jdt.ls.core.internal.preferences.Preferences;
import org.eclipse.jdt.ls.core.internal.text.correction.AssignToVariableAssistCommandProposal;
import org.eclipse.jdt.ls.core.internal.text.correction.CUCorrectionCommandProposal;
import org.eclipse.jdt.ls.core.internal.text.correction.NonProjectFixProcessor;
@@ -86,6 +91,32 @@ public List> getCodeActionCommands(CodeActionParams
return Collections.emptyList();
}
+ Map formattingOptions = ConfigurationHandler.getFormattingOptions(params.getTextDocument().getUri());
+ if (formattingOptions != null && !formattingOptions.isEmpty()) {
+ Object tabSizeValue = formattingOptions.get(Preferences.JAVA_CONFIGURATION_TABSIZE);
+ Object insertSpacesValue = formattingOptions.get(Preferences.JAVA_CONFIGURATION_INSERTSPACES);
+ Map customOptions = new HashMap<>();
+ if (tabSizeValue != null) {
+ try {
+ int tabSize = Integer.parseInt(String.valueOf(tabSizeValue));
+ if (tabSize > 0) {
+ customOptions.put(DefaultCodeFormatterConstants.FORMATTER_TAB_SIZE, Integer.toString(tabSize));
+ }
+ } catch (Exception ex) {
+ // do nothing
+ }
+ }
+
+ if (insertSpacesValue != null) {
+ boolean insertSpaces = Boolean.parseBoolean(String.valueOf(insertSpacesValue));
+ customOptions.put(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR, insertSpaces ? JavaCore.SPACE : JavaCore.TAB);
+ }
+
+ if (!customOptions.isEmpty()) {
+ unit.setOptions(customOptions);
+ }
+ }
+
CompilationUnit astRoot = getASTRoot(unit, monitor);
if (astRoot == null || monitor.isCanceled()) {
return Collections.emptyList();
diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/ConfigurationHandler.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/ConfigurationHandler.java
new file mode 100644
index 0000000000..0f26538551
--- /dev/null
+++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/ConfigurationHandler.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2020 Microsoft Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Microsoft Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.ls.core.internal.handlers;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin;
+import org.eclipse.jdt.ls.core.internal.preferences.Preferences;
+import org.eclipse.lsp4j.ConfigurationItem;
+import org.eclipse.lsp4j.ConfigurationParams;
+
+public class ConfigurationHandler {
+
+ private ConfigurationHandler() {}
+
+ /**
+ * Query the format setting (insertSpace and tabSize) for the given uri.
+ * Will return {@code null} if the 'workspace/configuration' request is not supported,
+ * @param uri The target uri to query
+ * @return a map stores the setting keys and their values, for any setting key which is not
+ * available at the client side, a {@code null} value will be provided.
+ */
+ public static Map getFormattingOptions(String uri) {
+ if (!JavaLanguageServerPlugin.getPreferencesManager().getClientPreferences().isWorkspaceConfigurationSupported()) {
+ return null;
+ };
+
+ List configurationItems = new ArrayList<>();
+ String[] settingKeys = {
+ Preferences.JAVA_CONFIGURATION_TABSIZE,
+ Preferences.JAVA_CONFIGURATION_INSERTSPACES
+ };
+
+ ConfigurationItem tabSizeItem = new ConfigurationItem();
+ tabSizeItem.setScopeUri(uri);
+ tabSizeItem.setSection(settingKeys[0]);
+ configurationItems.add(tabSizeItem);
+
+ ConfigurationItem insertSpacesItem = new ConfigurationItem();
+ insertSpacesItem.setScopeUri(uri);
+ insertSpacesItem.setSection(settingKeys[1]);
+ configurationItems.add(insertSpacesItem);
+
+ ConfigurationParams configurationParams = new ConfigurationParams(configurationItems);
+ List response = JavaLanguageServerPlugin.getInstance().getClientConnection().configuration(configurationParams);
+
+ Map results = new HashMap<>();
+ int minLength = Math.min(settingKeys.length, response.size());
+ for (int i = 0; i < minLength; i++) {
+ results.put(settingKeys[i], response.get(i));
+ }
+ return results;
+ }
+}
diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/FormatterHandler.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/FormatterHandler.java
index 99b1946415..906699fa51 100644
--- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/FormatterHandler.java
+++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/FormatterHandler.java
@@ -141,7 +141,7 @@ private IRegion getRegion(Range range, IDocument document) {
}
public static Map getOptions(FormattingOptions options, ICompilationUnit cu) {
- Map eclipseOptions = cu.getJavaProject().getOptions(true);
+ Map eclipseOptions = cu.getOptions(true);
Map customOptions = options.entrySet().stream().filter(map -> chekIfValueIsNotNull(map.getValue())).collect(toMap(e -> e.getKey(), e -> getOptionValue(e.getValue())));
diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/JDTLanguageServer.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/JDTLanguageServer.java
index ffab801d57..7999c7eacc 100644
--- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/JDTLanguageServer.java
+++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/JDTLanguageServer.java
@@ -41,6 +41,7 @@
import org.eclipse.jdt.ls.core.internal.JDTUtils;
import org.eclipse.jdt.ls.core.internal.JSONUtility;
import org.eclipse.jdt.ls.core.internal.JVMConfigurator;
+import org.eclipse.jdt.ls.core.internal.JavaClientConnection;
import org.eclipse.jdt.ls.core.internal.JavaClientConnection.JavaLanguageClient;
import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin;
import org.eclipse.jdt.ls.core.internal.JobHelpers;
@@ -214,6 +215,11 @@ public void connectClient(JavaLanguageClient client) {
this.documentLifeCycleHandler = new DocumentLifeCycleHandler(this.client, preferenceManager, pm, true);
}
+ // For testing purpose
+ public void setClientConnection(JavaClientConnection client) {
+ this.client = client;
+ }
+
//For testing purposes
public void disconnectClient() {
Job.getJobManager().setProgressProvider(null);
diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/WorkspaceSymbolHandler.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/WorkspaceSymbolHandler.java
index 32b8ebb202..b2b54faa9b 100644
--- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/WorkspaceSymbolHandler.java
+++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/WorkspaceSymbolHandler.java
@@ -64,6 +64,9 @@ public static List search(String query, int maxResults, Strin
@Override
public void acceptTypeNameMatch(TypeNameMatch match) {
try {
+ if (maxResults > 0 && symbols.size() >= maxResults) {
+ return;
+ }
Location location = null;
try {
if (!sourceOnly && match.getType().isBinary()) {
diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/ClientPreferences.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/ClientPreferences.java
index faed1d3193..38d1c4f56a 100644
--- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/ClientPreferences.java
+++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/ClientPreferences.java
@@ -119,6 +119,10 @@ public boolean isWorkspaceChangeWatchedFilesDynamicRegistered() {
return v3supported && capabilities.getWorkspace() != null && isDynamicRegistrationSupported(capabilities.getWorkspace().getDidChangeWatchedFiles());
}
+ public boolean isWorkspaceConfigurationSupported() {
+ return v3supported && capabilities.getWorkspace() != null && isTrue(capabilities.getWorkspace().getConfiguration());
+ }
+
public boolean isDocumentSymbolDynamicRegistered() {
return v3supported && isDynamicRegistrationSupported(capabilities.getTextDocument().getDocumentSymbol());
}
diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/Preferences.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/Preferences.java
index bbec4ec4da..574635b56a 100644
--- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/Preferences.java
+++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/Preferences.java
@@ -68,6 +68,14 @@ public class Preferences {
* references.
*/
public static final String JAVA_REFERENCES_INCLUDE_DECOMPILED_SOURCES = "java.references.includeDecompiledSources";
+ /**
+ * Insert spaces when pressing Tab
+ */
+ public static final String JAVA_CONFIGURATION_INSERTSPACES = "java.format.insertSpaces";
+ /**
+ * Tab Size
+ */
+ public static final String JAVA_CONFIGURATION_TABSIZE = "java.format.tabSize";
/**
* Specifies Java Execution Environments.
*/
diff --git a/org.eclipse.jdt.ls.target/org.eclipse.jdt.ls.tp.target b/org.eclipse.jdt.ls.target/org.eclipse.jdt.ls.tp.target
index c44e21edd9..15f82a831b 100644
--- a/org.eclipse.jdt.ls.target/org.eclipse.jdt.ls.tp.target
+++ b/org.eclipse.jdt.ls.target/org.eclipse.jdt.ls.tp.target
@@ -31,6 +31,9 @@
+
+
+
diff --git a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/correction/AbstractQuickFixTest.java b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/correction/AbstractQuickFixTest.java
index 0cdd9964aa..38a75760ea 100644
--- a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/correction/AbstractQuickFixTest.java
+++ b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/correction/AbstractQuickFixTest.java
@@ -302,13 +302,17 @@ protected String evaluateCodeActionCommand(Either codeActio
Assert.assertNotNull(c.getArguments());
Assert.assertTrue(c.getArguments().get(0) instanceof WorkspaceEdit);
WorkspaceEdit we = (WorkspaceEdit) c.getArguments().get(0);
- if (we.getDocumentChanges() != null) {
- return ResourceUtils.dos2Unix(evaluateChanges(we.getDocumentChanges()));
+ return evaluateWorkspaceEdit(we);
+ }
+
+ public static String evaluateWorkspaceEdit(WorkspaceEdit edit) throws JavaModelException, BadLocationException {
+ if (edit.getDocumentChanges() != null) {
+ return ResourceUtils.dos2Unix(evaluateChanges(edit.getDocumentChanges()));
}
- return ResourceUtils.dos2Unix(evaluateChanges(we.getChanges()));
+ return ResourceUtils.dos2Unix(evaluateChanges(edit.getChanges()));
}
- private String evaluateChanges(List> documentChanges) throws BadLocationException, JavaModelException {
+ public static String evaluateChanges(List> documentChanges) throws BadLocationException, JavaModelException {
List changes = documentChanges.stream().filter(e -> e.isLeft()).map(e -> e.getLeft()).collect(Collectors.toList());
assertFalse("No edits generated", changes.isEmpty());
Set uris = changes.stream().map(tde -> tde.getTextDocument().getUri()).distinct().collect(Collectors.toSet());
@@ -318,7 +322,7 @@ private String evaluateChanges(List>
return ResourceUtils.dos2Unix(evaluateChanges(uri, edits));
}
- protected String evaluateChanges(Map> changes) throws BadLocationException, JavaModelException {
+ public static String evaluateChanges(Map> changes) throws BadLocationException, JavaModelException {
Iterator>> editEntries = changes.entrySet().iterator();
Entry> entry = editEntries.next();
assertNotNull("No edits generated", entry);
@@ -326,7 +330,7 @@ protected String evaluateChanges(Map> changes) throws Bad
return ResourceUtils.dos2Unix(evaluateChanges(entry.getKey(), entry.getValue()));
}
- private String evaluateChanges(String uri, List edits) throws BadLocationException, JavaModelException {
+ private static String evaluateChanges(String uri, List edits) throws BadLocationException, JavaModelException {
assertFalse("No edits generated: " + edits, edits == null || edits.isEmpty());
ICompilationUnit cu = JDTUtils.resolveCompilationUnit(uri);
assertNotNull("CU not found: " + uri, cu);
diff --git a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/CodeActionHandlerTest.java b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/CodeActionHandlerTest.java
index 6813cec8f8..a00eddf7d6 100644
--- a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/CodeActionHandlerTest.java
+++ b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/CodeActionHandlerTest.java
@@ -14,27 +14,38 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.when;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jdt.core.ICompilationUnit;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.IPackageFragment;
+import org.eclipse.jdt.core.IPackageFragmentRoot;
+import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.compiler.IProblem;
+import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants;
import org.eclipse.jdt.ls.core.internal.CodeActionUtil;
import org.eclipse.jdt.ls.core.internal.JDTUtils;
import org.eclipse.jdt.ls.core.internal.JavaClientConnection;
import org.eclipse.jdt.ls.core.internal.JavaCodeActionKind;
import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin;
import org.eclipse.jdt.ls.core.internal.LanguageServerWorkingCopyOwner;
+import org.eclipse.jdt.ls.core.internal.ProjectUtils;
import org.eclipse.jdt.ls.core.internal.WorkspaceHelper;
+import org.eclipse.jdt.ls.core.internal.codemanipulation.AbstractSourceTestCase;
+import org.eclipse.jdt.ls.core.internal.correction.AbstractQuickFixTest;
+import org.eclipse.jdt.ls.core.internal.preferences.ClientPreferences;
import org.eclipse.jdt.ls.core.internal.preferences.PreferenceManager;
import org.eclipse.lsp4j.CodeAction;
import org.eclipse.lsp4j.CodeActionContext;
@@ -54,6 +65,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
/**
@@ -65,7 +77,7 @@ public class CodeActionHandlerTest extends AbstractCompilationUnitBasedTest {
@Mock
private JavaClientConnection connection;
-
+ private ClientPreferences clientPreferences;
@Override
@Before
@@ -76,6 +88,12 @@ public void setup() throws Exception{
server = new JDTLanguageServer(projectsManager, this.preferenceManager);
}
+ @Override
+ protected ClientPreferences initPreferenceManager(boolean supportClassFileContents) {
+ clientPreferences = super.initPreferenceManager(supportClassFileContents);
+ return clientPreferences;
+ }
+
@Test
public void testCodeAction_removeUnusedImport() throws Exception{
ICompilationUnit unit = getWorkingCopy(
@@ -440,6 +458,73 @@ public void testCodeAction_ignoringOtherDiagnosticWithoutCode() throws Exception
Assert.assertEquals(CodeActionHandler.COMMAND_ID_APPLY_EDIT, c.getCommand());
}
+ @Test
+ public void testCodeAction_customFileFormattingOptions() throws Exception {
+ when(clientPreferences.isWorkspaceConfigurationSupported()).thenReturn(true);
+ when(connection.configuration(Mockito.any())).thenReturn(Arrays.asList(4, true/*Indent using Spaces*/));
+ server.setClientConnection(connection);
+ JavaLanguageServerPlugin.getInstance().setProtocol(server);
+ IJavaProject javaProject = ProjectUtils.getJavaProject(project);
+ Map projectOptions = javaProject.getOptions(false);
+ projectOptions.put(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR, JavaCore.TAB); // Indent using Tabs
+ projectOptions.put(DefaultCodeFormatterConstants.FORMATTER_TAB_SIZE, "4");
+ javaProject.setOptions(projectOptions);
+
+ IPackageFragmentRoot sourceFolder = javaProject.getPackageFragmentRoot(project.getFolder("src"));
+ IPackageFragment pack1 = sourceFolder.createPackageFragment("test1", false, null);
+ StringBuilder builder = new StringBuilder();
+ builder.append("package test1;\n");
+ builder.append("interface I {\n");
+ builder.append(" void method();\n");
+ builder.append("}\n");
+ builder.append("public class E {\n");
+ builder.append(" void bar(I i) {\n");
+ builder.append(" }\n");
+ builder.append(" void foo() {\n");
+ builder.append(" bar(() /*[*//*]*/-> {\n");
+ builder.append(" });\n");
+ builder.append(" }\n");
+ builder.append("}\n");
+ ICompilationUnit cu = pack1.createCompilationUnit("E.java", builder.toString(), false, null);
+
+ CodeActionParams params = new CodeActionParams();
+ params.setTextDocument(new TextDocumentIdentifier(JDTUtils.toURI(cu)));
+ final Range range = CodeActionUtil.getRange(cu, "/*[*//*]*/");
+ params.setRange(range);
+ params.setContext(new CodeActionContext(Collections.emptyList(), Arrays.asList(CodeActionKind.Refactor)));
+ List> codeActions = getCodeActions(params);
+ Assert.assertNotNull(codeActions);
+ Optional> found = codeActions.stream().filter((codeAction) -> {
+ return codeAction.isRight() && Objects.equals("Convert to anonymous class creation", codeAction.getRight().getTitle());
+ }).findAny();
+ Assert.assertTrue(found.isPresent());
+
+ Either codeAction = found.get();
+ Command c = codeAction.isLeft() ? codeAction.getLeft() : codeAction.getRight().getCommand();
+ Assert.assertEquals(CodeActionHandler.COMMAND_ID_APPLY_EDIT, c.getCommand());
+ Assert.assertNotNull(c.getArguments());
+ Assert.assertTrue(c.getArguments().get(0) instanceof WorkspaceEdit);
+ WorkspaceEdit edit = (WorkspaceEdit) c.getArguments().get(0);
+ String actual = AbstractQuickFixTest.evaluateWorkspaceEdit(edit);
+ builder = new StringBuilder();
+ builder.append("package test1;\n");
+ builder.append("interface I {\n");
+ builder.append(" void method();\n");
+ builder.append("}\n");
+ builder.append("public class E {\n");
+ builder.append(" void bar(I i) {\n");
+ builder.append(" }\n");
+ builder.append(" void foo() {\n");
+ builder.append(" bar(new I() {\n");
+ builder.append(" @Override\n");
+ builder.append(" public void method() {\n");
+ builder.append(" }\n");
+ builder.append(" });\n");
+ builder.append(" }\n");
+ builder.append("}\n");
+ AbstractSourceTestCase.compareSource(builder.toString(), actual);
+ }
+
private List> getCodeActions(CodeActionParams params) {
return server.codeAction(params).join();
}
diff --git a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/ConfigurationHandlerTest.java b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/ConfigurationHandlerTest.java
new file mode 100644
index 0000000000..544d54d3fd
--- /dev/null
+++ b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/ConfigurationHandlerTest.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2020 Microsoft Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Microsoft Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.jdt.ls.core.internal.handlers;
+
+import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import org.eclipse.jdt.ls.core.internal.managers.AbstractProjectsManagerBasedTest;
+import org.eclipse.jdt.ls.core.internal.preferences.ClientPreferences;
+import org.junit.Test;
+
+public class ConfigurationHandlerTest extends AbstractProjectsManagerBasedTest {
+
+ @Test
+ public void testGetConfigurationWhenItIsNotSupported() {
+ ClientPreferences clientPreferences = mock(ClientPreferences.class);
+ when(clientPreferences.isWorkspaceConfigurationSupported()).thenReturn(false);
+ when(preferenceManager.getClientPreferences()).thenReturn(clientPreferences);
+
+ assertNull(ConfigurationHandler.getFormattingOptions("fakeUri"));
+ }
+}