Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support textDocument/selectionRange #1102

Merged
merged 5 commits into from Jul 11, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -215,6 +215,9 @@ InitializeResult initialize(InitializeParams param) {
if (!preferenceManager.getClientPreferences().isImplementationDynamicRegistered()) {
capabilities.setImplementationProvider(Boolean.TRUE);
}
if (!preferenceManager.getClientPreferences().isSelectionRangeDynamicRegistered()) {
capabilities.setSelectionRangeProvider(Boolean.TRUE);
}
TextDocumentSyncOptions textDocumentSyncOptions = new TextDocumentSyncOptions();
textDocumentSyncOptions.setOpenClose(Boolean.TRUE);
textDocumentSyncOptions.setSave(new SaveOptions(Boolean.TRUE));
Expand Down
Expand Up @@ -109,6 +109,8 @@
import org.eclipse.lsp4j.Registration;
import org.eclipse.lsp4j.RegistrationParams;
import org.eclipse.lsp4j.RenameParams;
import org.eclipse.lsp4j.SelectionRange;
import org.eclipse.lsp4j.SelectionRangeParams;
import org.eclipse.lsp4j.SignatureHelp;
import org.eclipse.lsp4j.SymbolInformation;
import org.eclipse.lsp4j.TextDocumentIdentifier;
Expand Down Expand Up @@ -242,6 +244,9 @@ public void initialized(InitializedParams params) {
if (preferenceManager.getClientPreferences().isImplementationDynamicRegistered()) {
registerCapability(Preferences.IMPLEMENTATION_ID, Preferences.IMPLEMENTATION);
}
if (preferenceManager.getClientPreferences().isSelectionRangeDynamicRegistered()) {
registerCapability(Preferences.SELECTION_RANGE_ID, Preferences.SELECTION_RANGE);
}
// we do not have the user setting initialized yet at this point but we should
// still call to enable defaults in case client does not support configuration changes
syncCapabilitiesToSettings();
Expand Down Expand Up @@ -305,6 +310,9 @@ private void syncCapabilitiesToSettings() {
if (preferenceManager.getClientPreferences().isFoldgingRangeDynamicRegistered()) {
toggleCapability(preferenceManager.getPreferences().isFoldingRangeEnabled(), Preferences.FOLDINGRANGE_ID, Preferences.FOLDINGRANGE, null);
}
if (preferenceManager.getClientPreferences().isSelectionRangeDynamicRegistered()) {
toggleCapability(preferenceManager.getPreferences().isSelectionRangeEnabled(), Preferences.SELECTION_RANGE_ID, Preferences.SELECTION_RANGE, null);
}
}

private CodeActionOptions getCodeActionOptions() {
Expand Down Expand Up @@ -774,6 +782,15 @@ public CompletableFuture<List<FoldingRange>> foldingRange(FoldingRangeRequestPar
});
}

@Override
public CompletableFuture<List<SelectionRange>> selectionRange(SelectionRangeParams params) {
logInfo(">> document/selectionRange");
return computeAsyncWithClientProgress((monitor) -> {
waitForLifecycleJobs(monitor);
return new SelectionRangeHandler().selectionRange(params, monitor);
});
}

@Override
public CompletableFuture<OverridableMethodsResponse> listOverridableMethods(CodeActionParams params) {
logInfo(">> java/listOverridableMethods");
Expand Down
@@ -0,0 +1,113 @@
/*******************************************************************************
* Copyright (c) 2019 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.List;
import java.util.ListIterator;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.core.ITypeRoot;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.Comment;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.Javadoc;
import org.eclipse.jdt.core.dom.NodeFinder;
import org.eclipse.jdt.core.manipulation.CoreASTProvider;
import org.eclipse.jdt.ls.core.internal.JDTUtils;
import org.eclipse.lsp4j.Position;
import org.eclipse.lsp4j.Range;
import org.eclipse.lsp4j.SelectionRange;
import org.eclipse.lsp4j.SelectionRangeParams;

public class SelectionRangeHandler {

public List<SelectionRange> selectionRange(SelectionRangeParams params, IProgressMonitor monitor) {
if (params.getPositions() == null || params.getPositions().size() <= 0) {
akaroml marked this conversation as resolved.
Show resolved Hide resolved
return null;
akaroml marked this conversation as resolved.
Show resolved Hide resolved
}

ITypeRoot root = JDTUtils.resolveTypeRoot(params.getTextDocument().getUri());
if (root == null) {
return null;
akaroml marked this conversation as resolved.
Show resolved Hide resolved
}

CompilationUnit ast = CoreASTProvider.getInstance().getAST(root, CoreASTProvider.WAIT_YES, monitor);

// extra logic to check within the line comments and block comments, which are not parts of the AST
@SuppressWarnings("unchecked")
List<Comment> comments = new ArrayList<Comment>(ast.getCommentList());
comments.removeIf(comment -> {
return (comment instanceof Javadoc); // Javadoc nodes are already in the AST
});

List<SelectionRange> $ = new ArrayList<>();
for (Position pos : params.getPositions()) {
try {
int offset = JsonRpcHelpers.toOffset(root.getBuffer(), pos.getLine(), pos.getCharacter());
ASTNode node = NodeFinder.perform(ast, offset, 0);
if (node == null) {
continue;
}

// find all the ancestors
List<ASTNode> nodes = new ArrayList<>();
while (node != null) {
nodes.add(node);
node = node.getParent();
}

// find all the ranges corresponding to the parent nodes
SelectionRange selectionRange = null;
ListIterator<ASTNode> iterator = nodes.listIterator(nodes.size());
while (iterator.hasPrevious()) {
node = iterator.previous();
Range range = JDTUtils.toRange(root, node.getStartPosition(), node.getLength());
selectionRange = new SelectionRange(range, selectionRange);
}

// find in comments
ASTNode containingComment = containingComment(comments, offset);
if (containingComment != null) {
Range range = JDTUtils.toRange(root, containingComment.getStartPosition(), containingComment.getLength());
selectionRange = new SelectionRange(range, selectionRange);
}

if (selectionRange != null) {
$.add(selectionRange);
}
} catch (JavaModelException e) {
e.printStackTrace();
akaroml marked this conversation as resolved.
Show resolved Hide resolved
}
}

return $;
}

/**
* Finds the comment that contains the specified position
*
* @param comments
* @param offset
* @return
*/
public ASTNode containingComment(List<Comment> comments, int offset) {
for (Comment comment : comments) {
ASTNode result = NodeFinder.perform(comment, offset, 0);
if (result != null) {
return result;
}
}

return null;
}
}
Expand Up @@ -149,6 +149,10 @@ public boolean isImplementationDynamicRegistered() {
return v3supported && isDynamicRegistrationSupported(capabilities.getTextDocument().getImplementation());
}

public boolean isSelectionRangeDynamicRegistered() {
return v3supported && isDynamicRegistrationSupported(capabilities.getTextDocument().getSelectionRange());
}

public boolean isWillSaveRegistered() {
return v3supported && capabilities.getTextDocument().getSynchronization() != null && isTrue(capabilities.getTextDocument().getSynchronization().getWillSave());
}
Expand Down
Expand Up @@ -169,6 +169,11 @@ public class Preferences {
*/
public static final String FOLDINGRANGE_ENABLED_KEY = "java.foldingRange.enabled";

/**
* Preference key to enable/disable the selection range.
*/
public static final String SELECTIONRANGE_ENABLED_KEY = "java.selectionRange.enabled";

/**
* A named preference that holds the favorite static members.
* <p>
Expand Down Expand Up @@ -270,6 +275,7 @@ public class Preferences {
public static final String FOLDINGRANGE = "textDocument/foldingRange";
public static final String WORKSPACE_CHANGE_FOLDERS = "workspace/didChangeWorkspaceFolders";
public static final String IMPLEMENTATION = "textDocument/implementation";
public static final String SELECTION_RANGE = "textDocument/selectionRange";

public static final String FORMATTING_ID = UUID.randomUUID().toString();
public static final String FORMATTING_ON_TYPE_ID = UUID.randomUUID().toString();
Expand All @@ -291,6 +297,7 @@ public class Preferences {
public static final String WORKSPACE_CHANGE_FOLDERS_ID = UUID.randomUUID().toString();
public static final String WORKSPACE_WATCHED_FILES_ID = UUID.randomUUID().toString();
public static final String IMPLEMENTATION_ID = UUID.randomUUID().toString();
public static final String SELECTION_RANGE_ID = UUID.randomUUID().toString();

private Map<String, Object> configuration;
private Severity incompleteClasspathSeverity;
Expand All @@ -315,6 +322,7 @@ public class Preferences {
private boolean completionEnabled;
private boolean completionOverwrite;
private boolean foldingRangeEnabled;
private boolean selectionRangeEnabled;
private boolean guessMethodArguments;
private boolean javaFormatComments;
private boolean hashCodeEqualsTemplateUseJava7Objects;
Expand Down Expand Up @@ -428,6 +436,7 @@ public Preferences() {
completionEnabled = true;
completionOverwrite = true;
foldingRangeEnabled = true;
selectionRangeEnabled = true;
guessMethodArguments = false;
javaFormatComments = true;
hashCodeEqualsTemplateUseJava7Objects = false;
Expand Down Expand Up @@ -514,6 +523,9 @@ public static Preferences createFrom(Map<String, Object> configuration) {
boolean foldingRangeEnable = getBoolean(configuration, FOLDINGRANGE_ENABLED_KEY, true);
prefs.setFoldingRangeEnabled(foldingRangeEnable);

boolean selectionRangeEnabled = getBoolean(configuration, SELECTIONRANGE_ENABLED_KEY, true);
prefs.setSelectionRangeEnabled(selectionRangeEnabled);

boolean guessMethodArguments = getBoolean(configuration, JAVA_COMPLETION_GUESS_METHOD_ARGUMENTS_KEY, false);
prefs.setGuessMethodArguments(guessMethodArguments);

Expand Down Expand Up @@ -707,6 +719,11 @@ public Preferences setFoldingRangeEnabled(boolean enabled) {
return this;
}

public Preferences setSelectionRangeEnabled(boolean enabled) {
this.selectionRangeEnabled = enabled;
return this;
}

public Preferences setGuessMethodArguments(boolean guessMethodArguments) {
this.guessMethodArguments = guessMethodArguments;
return this;
Expand Down Expand Up @@ -901,6 +918,10 @@ public boolean isFoldingRangeEnabled() {
return foldingRangeEnabled;
}

public boolean isSelectionRangeEnabled() {
return selectionRangeEnabled;
}

public boolean isGuessMethodArguments() {
return guessMethodArguments;
}
Expand Down
4 changes: 2 additions & 2 deletions org.eclipse.jdt.ls.target/org.eclipse.jdt.ls.tp.target
Expand Up @@ -37,8 +37,8 @@
<repository location="http://download.eclipse.org/releases/2019-06/"/>
</location>
<location includeAllPlatforms="false" includeConfigurePhase="false" includeMode="planner" includeSource="true" type="InstallableUnit">
<unit id="org.eclipse.lsp4j.sdk.feature.group" version="0.7.2.v20190528-0935"/>
<repository location="http://download.eclipse.org/lsp4j/updates/releases/0.7.2"/>
<repository location="https://github.com/akaroml/lsp4j-latest/raw/master/p2/"/>
akaroml marked this conversation as resolved.
Show resolved Hide resolved
<unit id="org.eclipse.lsp4j.sdk.feature.group" version="0.8.0.v20190701-0317"/>
</location>
<location includeAllPlatforms="false" includeConfigurePhase="false" includeMode="planner" includeSource="true" type="InstallableUnit">
<unit id="org.jboss.tools.maven.apt.core" version="0.0.0"/>
Expand Down
@@ -0,0 +1,32 @@
package java;
akaroml marked this conversation as resolved.
Show resolved Hide resolved

/**
* This is the test data for SelectionRangeHandlerTest. To ask for a selection range, we need to specify a position.
* To make those positions visible, >< pairs are used if possible, and a position is what's between > and <.
* All other positions are specified in the test code dierectly.
*/
class Foo4 {
/**
* Class constructor to test >< Javadoc
*/
Foo4() {
System.out.println("string >< literal"); // test line >< comment

/* test block >< comment */
memberFunc(1, 0.0);
}

void memberFunc(int paramA/* test block >< comment in param list */, double paramB) {
try {
switch(paramA) {
case 0:
System.out.println(paramB);
break;
default:
System.out.println();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}