PT #155266751: Eclipse source links via IntroURL

This commit is contained in:
BoykoAlex
2018-03-02 22:51:54 -05:00
parent 0220cf41bd
commit d13ccfc5c4
7 changed files with 360 additions and 1 deletions

View File

@@ -20,7 +20,9 @@ Require-Bundle: org.eclipse.jdt.launching;bundle-version="3.9.0",
org.eclipse.xtext.xbase.lib,
org.springframework.tooling.ls.eclipse.commons;bundle-version="0.2.0",
org.eclipse.core.resources,
org.eclipse.ui
org.eclipse.ui,
org.eclipse.ui.ide,
org.eclipse.jdt.core
Import-Package: com.google.gson;version="2.7.0",
org.eclipse.jface.preference,
org.osgi.framework

View File

@@ -99,6 +99,40 @@
class="org.springframework.tooling.boot.ls.PrefsInitializer">
</initializer>
</extension>
<extension
point="org.eclipse.ui.handlers">
<handler
class="org.springframework.tooling.boot.ls.commands.OpenFullyQualifiedNameInEditor"
commandId="org.springframework.tooling.boot.ls.OpenJavaType">
</handler>
<handler
class="org.springframework.tooling.boot.ls.commands.OpenResourceInEditor"
commandId="org.springframework.tooling.boot.ls.OpenResourceInEditor">
</handler>
</extension>
<extension
point="org.eclipse.ui.commands">
<command
id="org.springframework.tooling.boot.ls.OpenJavaType"
name="Open Java Type in Editor">
<commandParameter
id="fqName"
name="fqName"
optional="false">
</commandParameter>
</command>
<command
id="org.springframework.tooling.boot.ls.OpenResourceInEditor"
name="Open File in Editor">
<commandParameter
id="path"
name="path"
optional="false">
</commandParameter>
</command>
</extension>
<!--
<extension
point="org.eclipse.ui.editors">

View File

@@ -41,6 +41,7 @@ public class SpringBootLanguageServer extends STS4LanguageServerProcessStreamCon
// commands.add("-Xdebug");
// commands.add("-Xrunjdwp:server=y,transport=dt_socket,address=4000,suspend=n");
commands.add("-Dsts.lsp.client=eclipse");
commands.add("-Dlsp.lazy.completions.disable=true");
commands.add("-Dlsp.completions.indentation.enable=true");
commands.add("-Xmx1024m");

View File

@@ -0,0 +1,141 @@
/*******************************************************************************
* Copyright (c) 2018 Pivotal, Inc.
* 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:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.tooling.boot.ls.commands;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.WorkingCopyOwner;
import org.eclipse.jdt.core.search.IJavaSearchConstants;
import org.eclipse.jdt.core.search.IJavaSearchScope;
import org.eclipse.jdt.core.search.SearchEngine;
import org.eclipse.jdt.core.search.SearchPattern;
import org.eclipse.jdt.core.search.TypeNameMatch;
import org.eclipse.jdt.core.search.TypeNameMatchRequestor;
import org.eclipse.jdt.internal.core.search.JavaSearchScope;
import org.eclipse.jdt.ui.JavaUI;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.PartInitException;
import org.springframework.tooling.boot.ls.BootLanguageServerPlugin;
/**
* Command for opening Java type given by its fully qualified name in an editor
*
* @author Alex Boyko
*
*/
public class OpenFullyQualifiedNameInEditor extends AbstractHandler {
private static final String FQ_NAME = "fqName";
private static final String PROJECT_NAME = "projectName";
@Override
public Object execute(ExecutionEvent event) throws ExecutionException {
String fqName = event.getParameter(FQ_NAME);
String projectName = event.getParameter(PROJECT_NAME);
String packageName = "";
String typeName = fqName;
int idx = fqName.lastIndexOf('.');
if (idx >= 0) {
packageName = fqName.substring(0, idx);
typeName = idx < fqName.length() - 1 ? fqName.substring(idx + 1) : "";
}
if (!typeName.isEmpty()) {
SearchEngine engine= new SearchEngine((WorkingCopyOwner) null);
List<TypeNameMatch> matches = new ArrayList<>();
String searchedTypeName = getSearchedTypeName(typeName);
final boolean isInnerType = searchedTypeName != typeName;
TypeNameMatchRequestor requestor = new TypeNameMatchRequestor() {
@Override
public void acceptTypeNameMatch(TypeNameMatch match) {
if (isInnerType) {
if (match.getFullyQualifiedName().equals(fqName.replace("$", "."))) {
matches.add(match);
}
} else {
matches.add(match);
}
}
};
try {
IJavaSearchScope searchScope = createSearchScope(projectName);
engine.searchAllTypeNames(packageName.toCharArray(), SearchPattern.R_EXACT_MATCH,
searchedTypeName.toCharArray(), SearchPattern.R_EXACT_MATCH, IJavaSearchConstants.TYPE, searchScope,
requestor, IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH, new NullProgressMonitor());
if (matches.isEmpty()) {
BootLanguageServerPlugin.getDefault().getLog().log(new Status(IStatus.WARNING, BootLanguageServerPlugin.ID, "Cannot find type: " + fqName));
} else {
if (matches.size() > 1) {
BootLanguageServerPlugin.getDefault().getLog().log(new Status(IStatus.WARNING, BootLanguageServerPlugin.ID, "More than one type is defined for: " + fqName));
}
try {
IType type = matches.get(0).getType();
IEditorPart editorPart= JavaUI.openInEditor(type);
JavaUI.revealInEditor(editorPart, (IJavaElement)type);
} catch (JavaModelException ex) {
throw new ExecutionException("Error opening java element in editor", ex); //$NON-NLS-1$
} catch (PartInitException ex) {
throw new ExecutionException("Error opening java element in editor", ex); //$NON-NLS-1$
}
}
} catch (JavaModelException e) {
BootLanguageServerPlugin.getDefault().getLog().log(e.getStatus());
}
}
return null;
}
private String getSearchedTypeName(String typeName) {
int idx = typeName.lastIndexOf('$');
if (idx >= 0 && idx < typeName.length()) {
return typeName.substring(idx + 1);
}
return typeName;
}
private IJavaSearchScope createSearchScope(String projectName) {
try {
if (projectName != null) {
IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
if (project != null) {
IJavaProject javaProject = JavaCore.create(project);
if (javaProject != null) {
JavaSearchScope scope = new JavaSearchScope(false);
scope.add(javaProject);
return scope;
}
}
}
} catch (Throwable t) {
BootLanguageServerPlugin.getDefault().getLog().log(new Status(IStatus.WARNING, BootLanguageServerPlugin.ID, "Failed creating Java search scope for project: " + projectName));
}
return SearchEngine.createWorkspaceScope();
}
}

View File

@@ -0,0 +1,72 @@
/*******************************************************************************
* Copyright (c) 2018 Pivotal, Inc.
* 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:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.tooling.boot.ls.commands;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.ide.IDE;
/**
* Command for opening an editor given URI of the resource. (Platform command
* takes platform URI or path relative to the workspace)
*
* @author Alex Boyko
*
*/
public class OpenResourceInEditor extends AbstractHandler {
private static final String PATH = "path";
@Override
public Object execute(ExecutionEvent event) throws ExecutionException {
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
IPath rootPath = root.getLocation();
IPath resourcePath = new Path(event.getParameter(PATH));
IResource resource = root.findMember(resourcePath.makeRelativeTo(rootPath));
if (resource == null && !(resource instanceof IFile)) {
throw new ExecutionException("cannot find file: " + event.getParameter(PATH)); //$NON-NLS-1$
}
final IWorkbenchWindow window = PlatformUI.getWorkbench()
.getActiveWorkbenchWindow();
if (window == null) {
throw new ExecutionException("no active workbench window"); //$NON-NLS-1$
}
final IWorkbenchPage page = window.getActivePage();
if (page == null) {
throw new ExecutionException("no active workbench page"); //$NON-NLS-1$
}
try {
IDE.openEditor(page, (IFile) resource, true);
} catch (final PartInitException e) {
throw new ExecutionException("error opening file in editor", e); //$NON-NLS-1$
}
return null;
}
}

View File

@@ -0,0 +1,107 @@
/*******************************************************************************
* Copyright (c) 2018 Pivotal, Inc.
* 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:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.links;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
/**
* Source links for Eclipse client. Eclipse IntroURLs.
*
* @author Alex Boyko
*
*/
public class EclipseSourceLinks implements SourceLinks {
private static final String URL_PREFIX = "http://org.eclipse.ui.intro/execute?command=";
private static final String EQUALS = "=";
private static final String PARAMETERS_SEPARATOR = ",";
private static final String PARAMETERS_START = "(";
private static final String PARAMETERS_END = ")";
private static final String JAVA_TYPE_COMMAND = "org.springframework.tooling.boot.ls.OpenJavaType";
private static final String FQ_NAME_PARAMETER_ID = "fqName";
private static final String PROJECT_NAME_PARAMETER_ID = "projectName";
private static final String RESOURCE_COMMAND = "org.springframework.tooling.boot.ls.OpenResourceInEditor";
private static final String PATH = "path";
private static final Supplier<Logger> LOG = Suppliers.memoize(() -> LoggerFactory.getLogger(EclipseSourceLinks.class));
@Override
public Optional<String> sourceLinkUrlForFQName(IJavaProject project, String fqName) {
try {
StringBuilder paramBuilder = new StringBuilder(JAVA_TYPE_COMMAND);
paramBuilder.append(PARAMETERS_START);
paramBuilder.append(FQ_NAME_PARAMETER_ID);
paramBuilder.append(EQUALS);
paramBuilder.append(fqName);
if (project != null && project.getElementName() != null) {
paramBuilder.append(PARAMETERS_SEPARATOR);
paramBuilder.append(PROJECT_NAME_PARAMETER_ID);
paramBuilder.append(EQUALS);
paramBuilder.append(project.getElementName());
}
paramBuilder.append(PARAMETERS_END);
StringBuilder urlBuilder = new StringBuilder(URL_PREFIX);
urlBuilder.append(URLEncoder.encode(paramBuilder.toString(), "UTF8"));
return Optional.of(urlBuilder.toString());
} catch (UnsupportedEncodingException e) {
LOG.get().error("{}", e);
}
return Optional.empty();
}
@Override
public Optional<String> sourceLinkUrlForClasspathResource(IJavaProject project, String path) {
int idx = path.lastIndexOf(CLASS);
if (idx >= 0) {
Path p = Paths.get(path.substring(0, idx));
return sourceLinkUrlForFQName(project, p.toString().replace(File.separator, "."));
}
return Optional.empty();
}
@Override
public Optional<String> sourceLinkForResourcePath(Path path) {
try {
if (path != null) {
StringBuilder paramBuilder = new StringBuilder(RESOURCE_COMMAND);
paramBuilder.append(PARAMETERS_START);
paramBuilder.append(PATH);
paramBuilder.append(EQUALS);
paramBuilder.append(path);
paramBuilder.append(PARAMETERS_END);
StringBuilder urlBuilder = new StringBuilder(URL_PREFIX);
urlBuilder.append(URLEncoder.encode(paramBuilder.toString(), "UTF8"));
return Optional.of(urlBuilder.toString());
}
} catch (UnsupportedEncodingException e) {
LOG.get().error("{}", e);
}
return Optional.empty();
}
}

View File

@@ -53,6 +53,8 @@ public final class SourceLinkFactory {
switch (LspClient.currentClient()) {
case VSCODE:
return new VSCodeSourceLinks(server);
case ECLIPSE:
return new EclipseSourceLinks();
default:
return NO_SOURCE_LINKS;
}