blob: e427a89fb674b9960ffedd320db88d14f580275a [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.lsp.client.bindings;
import java.net.MalformedURLException;
import java.net.URI;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import javax.swing.SwingUtilities;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import org.eclipse.lsp4j.Location;
import org.eclipse.lsp4j.LocationLink;
import org.eclipse.lsp4j.Range;
import org.eclipse.lsp4j.TextDocumentIdentifier;
import org.eclipse.lsp4j.TextDocumentPositionParams;
import org.eclipse.lsp4j.jsonrpc.messages.Either;
import org.netbeans.api.editor.mimelookup.MimeRegistration;
import org.netbeans.editor.BaseDocument;
import org.netbeans.editor.Utilities;
import org.netbeans.lib.editor.hyperlink.spi.HyperlinkProviderExt;
import org.netbeans.lib.editor.hyperlink.spi.HyperlinkType;
import org.netbeans.modules.editor.NbEditorUtilities;
import org.netbeans.modules.lsp.client.LSPBindings;
import org.netbeans.modules.lsp.client.Utils;
import org.openide.cookies.LineCookie;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.URLMapper;
import org.openide.text.Line;
import org.openide.text.Line.ShowOpenType;
import org.openide.text.Line.ShowVisibilityType;
import org.openide.util.Exceptions;
/**
*
* @author lahvac
*/
@MimeRegistration(mimeType="", service=HyperlinkProviderExt.class)
public class HyperlinkProviderImpl implements HyperlinkProviderExt {
@Override
public Set<HyperlinkType> getSupportedHyperlinkTypes() {
return EnumSet.of(HyperlinkType.GO_TO_DECLARATION);
}
@Override
public boolean isHyperlinkPoint(Document doc, int offset, HyperlinkType type) {
return getHyperlinkSpan(doc, offset, type) != null;
}
@Override
public int[] getHyperlinkSpan(Document doc, int offset, HyperlinkType type) {
if (doc.getProperty(HyperlinkProviderImpl.class) != Boolean.TRUE) {
//not handled by a LSP handler
return null;
}
try {
//XXX: not really using the server, are we?
return Utilities.getIdentifierBlock((BaseDocument) doc, offset);
} catch (BadLocationException ex) {
return null;
}
}
@Override
public void performClickAction(Document doc, int offset, HyperlinkType type) {
FileObject file = NbEditorUtilities.getFileObject(doc);
if (file == null) {
//TODO: beep
return ;
}
LSPBindings server = LSPBindings.getBindings(file);
if (server == null) {
return ;
}
String uri = Utils.toURI(file);
try {
TextDocumentPositionParams params;
params = new TextDocumentPositionParams(new TextDocumentIdentifier(uri),
Utils.createPosition(doc, offset));
//TODO: Location or Location[]
CompletableFuture<Either<List<? extends Location>, List<? extends LocationLink>>> def = server.getTextDocumentService().definition(params);
def.handleAsync((locations, exception) -> {
if (exception != null) {
exception.printStackTrace();
}
if (locations == null) {
return null;
}
String targetUri;
Range targetRange;
if (locations.isLeft() && locations.getLeft().size() == 1) { //TODO: what to do when there are multiple locations?
targetUri = locations.getLeft().get(0).getUri();
targetRange = locations.getLeft().get(0).getRange();
} else if (locations.isRight() && locations.getRight().size() == 1) { //TODO: what to do when there are multiple locations?
targetUri = locations.getRight().get(0).getTargetUri();
targetRange = locations.getRight().get(0).getTargetRange();
} else {
return null;
}
try {
URI target = URI.create(targetUri);
FileObject targetFile = URLMapper.findFileObject(target.toURL());
if (targetFile != null) {
LineCookie lc = targetFile.getLookup().lookup(LineCookie.class);
//TODO: expecting lc != null!
Line line = lc.getLineSet().getCurrent(targetRange.getStart().getLine());
SwingUtilities.invokeLater(() ->
line.show(ShowOpenType.OPEN, ShowVisibilityType.FOCUS, targetRange.getStart().getCharacter())
);
} else {
//TODO: beep
}
} catch (MalformedURLException ex) {
Exceptions.printStackTrace(ex);
}
return null;
}).get();
} catch (BadLocationException ex) {
Exceptions.printStackTrace(ex);
} catch (InterruptedException ex) {
Exceptions.printStackTrace(ex);
} catch (ExecutionException ex) {
Exceptions.printStackTrace(ex);
}
}
@Override
public String getTooltipText(Document doc, int offset, HyperlinkType type) {
return null;
}
}