backport: feat: Documentation link handler
This commit is contained in:
parent
b37233fdfd
commit
277b59ef38
4 changed files with 102 additions and 6 deletions
|
@ -0,0 +1,92 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2023-2024 FalsePattern
|
||||||
|
*
|
||||||
|
* Licensed 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 com.falsepattern.zigbrains.lsp.contributors;
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.lsp.utils.DocumentUtils;
|
||||||
|
import com.falsepattern.zigbrains.lsp.utils.FileUtils;
|
||||||
|
import com.intellij.openapi.application.ApplicationManager;
|
||||||
|
import com.intellij.openapi.diagnostic.Logger;
|
||||||
|
import com.intellij.openapi.editor.ScrollType;
|
||||||
|
import com.intellij.openapi.fileEditor.FileEditorManager;
|
||||||
|
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
|
||||||
|
import com.intellij.openapi.vfs.VfsUtil;
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile;
|
||||||
|
import com.intellij.platform.backend.documentation.DocumentationLinkHandler;
|
||||||
|
import com.intellij.platform.backend.documentation.DocumentationTarget;
|
||||||
|
import com.intellij.platform.backend.documentation.LinkResolveResult;
|
||||||
|
import lombok.val;
|
||||||
|
import org.eclipse.lsp4j.Position;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
import static com.intellij.codeInsight.documentation.DocumentationManagerProtocol.PSI_ELEMENT_PROTOCOL;
|
||||||
|
|
||||||
|
public class LSPDocumentationLinkHandler implements DocumentationLinkHandler {
|
||||||
|
private static final String prefix = PSI_ELEMENT_PROTOCOL + "zigbrains://";
|
||||||
|
private final static Logger LOG = Logger.getInstance(LSPDocumentationLinkHandler.class);
|
||||||
|
@Override
|
||||||
|
public @Nullable LinkResolveResult resolveLink(@NotNull DocumentationTarget target, @NotNull String url) {
|
||||||
|
if (!url.startsWith(PSI_ELEMENT_PROTOCOL) || ! (target instanceof LSPDocumentationTargetProvider.LSPDocumentationTarget tgt)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
url = url.replace(prefix, "file://");
|
||||||
|
val separator = url.indexOf("#L");
|
||||||
|
if (separator < 0)
|
||||||
|
return null;
|
||||||
|
val link = url.substring(0, separator);
|
||||||
|
final int line;
|
||||||
|
{
|
||||||
|
int theLine = 1;
|
||||||
|
try {
|
||||||
|
theLine = Integer.parseInt(url.substring(separator + 2));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
LOG.error("Could not parse file line: " + url.substring(separator + 2));
|
||||||
|
}
|
||||||
|
line = theLine - 1;
|
||||||
|
}
|
||||||
|
val app = ApplicationManager.getApplication();
|
||||||
|
app.executeOnPooledThread(() -> {
|
||||||
|
val project = tgt.file.getProject();
|
||||||
|
VirtualFile file;
|
||||||
|
try {
|
||||||
|
file = VfsUtil.findFileByURL(new URL(link));
|
||||||
|
} catch (MalformedURLException e1) {
|
||||||
|
LOG.warn("Syntax Exception occurred for uri: " + link);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (file == null)
|
||||||
|
return;
|
||||||
|
val descriptor = new OpenFileDescriptor(project, file);
|
||||||
|
app.invokeLater(() -> {
|
||||||
|
FileEditorManager.getInstance(project).openTextEditor(descriptor, true);
|
||||||
|
val editor = FileUtils.editorFromVirtualFile(file, project);
|
||||||
|
if (editor == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
val logicalPos = DocumentUtils.getTabsAwarePosition(editor, new Position(line, 0));
|
||||||
|
if (logicalPos == null)
|
||||||
|
return;
|
||||||
|
editor.getCaretModel().moveToLogicalPosition(logicalPos);
|
||||||
|
editor.getScrollingModel().scrollTo(logicalPos, ScrollType.CENTER);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -47,6 +47,8 @@ import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
import static com.intellij.codeInsight.documentation.DocumentationManagerProtocol.PSI_ELEMENT_PROTOCOL;
|
||||||
|
|
||||||
public class LSPDocumentationTargetProvider implements DocumentationTargetProvider {
|
public class LSPDocumentationTargetProvider implements DocumentationTargetProvider {
|
||||||
@Override
|
@Override
|
||||||
public @NotNull List<? extends @NotNull DocumentationTarget> documentationTargets(@NotNull PsiFile file, int offset) {
|
public @NotNull List<? extends @NotNull DocumentationTarget> documentationTargets(@NotNull PsiFile file, int offset) {
|
||||||
|
@ -58,7 +60,7 @@ public class LSPDocumentationTargetProvider implements DocumentationTargetProvid
|
||||||
|
|
||||||
public static class LSPDocumentationTarget implements DocumentationTarget {
|
public static class LSPDocumentationTarget implements DocumentationTarget {
|
||||||
private final Pointer<LSPDocumentationTarget> pointer;
|
private final Pointer<LSPDocumentationTarget> pointer;
|
||||||
private final PsiFile file;
|
public final PsiFile file;
|
||||||
private final int offset;
|
private final int offset;
|
||||||
public LSPDocumentationTarget(PsiFile file, int offset) {
|
public LSPDocumentationTarget(PsiFile file, int offset) {
|
||||||
this.file = file;
|
this.file = file;
|
||||||
|
@ -103,7 +105,7 @@ public class LSPDocumentationTargetProvider implements DocumentationTargetProvid
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
val markdown = HoverHandler.getHoverString(hover);
|
val markdown = HoverHandler.getHoverString(hover).replaceAll("file://", PSI_ELEMENT_PROTOCOL + "zigbrains://");
|
||||||
val string = ApplicationUtil.computableReadAction(() -> DocMarkdownToHtmlConverter
|
val string = ApplicationUtil.computableReadAction(() -> DocMarkdownToHtmlConverter
|
||||||
.convert(manager.getProject(), markdown));
|
.convert(manager.getProject(), markdown));
|
||||||
if (StringUtils.isEmpty(string)) {
|
if (StringUtils.isEmpty(string)) {
|
||||||
|
|
|
@ -161,7 +161,7 @@ import static com.falsepattern.zigbrains.lsp.utils.GUIUtils.createAndShowEditorH
|
||||||
public class EditorEventManager {
|
public class EditorEventManager {
|
||||||
|
|
||||||
public final DocumentEventManager documentEventManager;
|
public final DocumentEventManager documentEventManager;
|
||||||
protected Logger LOG = Logger.getInstance(EditorEventManager.class);
|
protected static Logger LOG = Logger.getInstance(EditorEventManager.class);
|
||||||
|
|
||||||
public Editor editor;
|
public Editor editor;
|
||||||
public LanguageServerWrapper wrapper;
|
public LanguageServerWrapper wrapper;
|
||||||
|
@ -1294,7 +1294,7 @@ public class EditorEventManager {
|
||||||
if (loc == null)
|
if (loc == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return gotoLocation(loc);
|
return gotoLocation(project, loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tries to go to declaration / show usages based on the element which is
|
// Tries to go to declaration / show usages based on the element which is
|
||||||
|
@ -1325,11 +1325,11 @@ public class EditorEventManager {
|
||||||
referencesAction.forManagerAndOffset(this, sourceOffset);
|
referencesAction.forManagerAndOffset(this, sourceOffset);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
gotoLocation(loc);
|
gotoLocation(project, loc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean gotoLocation(Location loc) {
|
public static boolean gotoLocation(Project project, Location loc) {
|
||||||
VirtualFile file = null;
|
VirtualFile file = null;
|
||||||
try {
|
try {
|
||||||
file = VfsUtil.findFileByURL(new URL(loc.getUri()));
|
file = VfsUtil.findFileByURL(new URL(loc.getUri()));
|
||||||
|
|
|
@ -108,6 +108,8 @@
|
||||||
bundle="zigbrains.zig.Bundle"
|
bundle="zigbrains.zig.Bundle"
|
||||||
key="notif-zls"
|
key="notif-zls"
|
||||||
id="ZigBrains.ZLS"/>
|
id="ZigBrains.ZLS"/>
|
||||||
|
|
||||||
|
<platform.backend.documentation.linkHandler implementation="com.falsepattern.zigbrains.lsp.contributors.LSPDocumentationLinkHandler"/>
|
||||||
</extensions>
|
</extensions>
|
||||||
|
|
||||||
<extensions defaultExtensionNs="com.falsepattern.zigbrains">
|
<extensions defaultExtensionNs="com.falsepattern.zigbrains">
|
||||||
|
|
Loading…
Add table
Reference in a new issue