Skip to content

Commit

Permalink
refactor: extracted methods to improve readability
Browse files Browse the repository at this point in the history
Signed-off-by: Andre Dietisheim <[email protected]>
  • Loading branch information
adietish committed Jun 29, 2023
1 parent c98c8f8 commit f8890f6
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 80 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import com.intellij.codeInsight.hints.presentation.InlayPresentation;
import com.intellij.codeInsight.hints.presentation.PresentationFactory;
import com.intellij.codeInsight.hints.presentation.SequencePresentation;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
Expand Down Expand Up @@ -64,53 +65,72 @@ public InlayHintsCollector getCollectorFor(@NotNull PsiFile psiFile,
@Override
public boolean collect(@NotNull PsiElement psiElement, @NotNull Editor editor, @NotNull InlayHintsSink inlayHintsSink) {
try {
Document document = editor.getDocument();
Project project = psiElement.getProject();
if (project.isDisposed()) {
// The project has been closed, don't collect code lenses.
return false;
}
URI docURI = LSPIJUtils.toUri(editor.getDocument());
URI docURI = LSPIJUtils.toUri(document);
if (docURI != null) {
CodeLensParams param = new CodeLensParams(new TextDocumentIdentifier(docURI.toString()));
BlockingDeque<Pair<CodeLens, LanguageServer>> pairs = new LinkedBlockingDeque<>();
List<Pair<Integer, Pair<CodeLens, LanguageServer>>> codelenses = new ArrayList<>();
CompletableFuture<Void> future = LanguageServiceAccessor.getInstance(project)
.getLanguageServers(editor.getDocument(), capabilities -> capabilities.getCodeLensProvider() != null)
.thenComposeAsync(languageServers -> CompletableFuture.allOf(languageServers.stream()
.map(languageServer -> languageServer.getSecond().getTextDocumentService().codeLens(param)
.thenAcceptAsync(codeLenses -> {
// textDocument/codeLens may return null
if (codeLenses != null) {
codeLenses.stream().filter(Objects::nonNull)
.forEach(codeLens -> pairs.add(new Pair(codeLens, languageServer.getSecond())));
}
}))
.toArray(CompletableFuture[]::new)));
while (!future.isDone() || !pairs.isEmpty()) {
ProgressManager.checkCanceled();
Pair<CodeLens, LanguageServer> pair = pairs.poll(25, TimeUnit.MILLISECONDS);
if (pair != null) {
int offset = LSPIJUtils.toOffset(pair.getFirst().getRange().getStart(), editor.getDocument());
codelenses.add(Pair.create(offset, pair));
}
}
Map<Integer, List<Pair<Integer, Pair<CodeLens, LanguageServer>>>> elements = codelenses.stream().collect(Collectors.groupingBy(p -> p.first));
elements.forEach((offset, list) -> inlayHintsSink.addBlockElement(offset, true,
true, 0, toPresentation(editor, offset, list, getFactory())));
CompletableFuture<Void> future = collect(document, project, param, pairs);
List<Pair<Integer, Pair<CodeLens, LanguageServer>>> codeLenses = createCodeLenses(document, pairs, future);
Map<Integer, List<Pair<Integer, Pair<CodeLens, LanguageServer>>>> elements = codeLenses.stream().collect(Collectors.groupingBy(p -> p.first));
elements.forEach((offset, list) ->
inlayHintsSink.addBlockElement(
offset,
true,
true,
0,
toPresentation(editor, offset, list, getFactory()))
);
}
} catch (InterruptedException e) {
LOGGER.warn(e.getLocalizedMessage(), e);
Thread.currentThread().interrupt();
}
return false;
}

@NotNull
private List<Pair<Integer, Pair<CodeLens, LanguageServer>>> createCodeLenses(Document document, BlockingDeque<Pair<CodeLens, LanguageServer>> pairs, CompletableFuture<Void> future) throws InterruptedException {
List<Pair<Integer, Pair<CodeLens, LanguageServer>>> codelenses = new ArrayList<>();
while (!future.isDone() || !pairs.isEmpty()) {
ProgressManager.checkCanceled();
Pair<CodeLens, LanguageServer> pair = pairs.poll(25, TimeUnit.MILLISECONDS);
if (pair != null) {
int offset = LSPIJUtils.toOffset(pair.getFirst().getRange().getStart(), document);
codelenses.add(Pair.create(offset, pair));
}
}
return codelenses;
}

private CompletableFuture<Void> collect(Document document, Project project, CodeLensParams param, BlockingDeque<Pair<CodeLens, LanguageServer>> pairs) {
return LanguageServiceAccessor.getInstance(project)
.getLanguageServers(document, capabilities -> capabilities.getCodeLensProvider() != null)
.thenComposeAsync(languageServers -> CompletableFuture.allOf(languageServers.stream()
.map(languageServer -> languageServer.getSecond().getTextDocumentService().codeLens(param)
.thenAcceptAsync(codeLenses -> {
// textDocument/codeLens may return null
if (codeLenses != null) {
codeLenses.stream().filter(Objects::nonNull)
.forEach(codeLens -> pairs.add(new Pair(codeLens, languageServer.getSecond())));
}
}))
.toArray(CompletableFuture[]::new)));
}
};
}

private InlayPresentation toPresentation(Editor editor, int offset,
List<Pair<Integer, Pair<CodeLens, LanguageServer>>> elements,
PresentationFactory factory) {

private InlayPresentation toPresentation(
Editor editor,
int offset,
List<Pair<Integer, Pair<CodeLens, LanguageServer>>> elements,
PresentationFactory factory
) {
int line = editor.getDocument().getLineNumber(offset);
int column = offset - editor.getDocument().getLineStartOffset(line);
List<InlayPresentation> presentations = new ArrayList<>();
Expand All @@ -124,9 +144,9 @@ private InlayPresentation toPresentation(Editor editor, int offset,
presentations.add(text);
} else {
// Codelens defines a Command, create a clickable inlay hint
InlayPresentation clickableText = factory.referenceOnHover(text, (event, translated) -> {
executeClientCommand(p.second.second, p.second.first, (Component) event.getSource(), editor.getProject());
});
InlayPresentation clickableText = factory.referenceOnHover(text, (event, translated) ->
executeClientCommand(p.second.second, p.second.first, (Component) event.getSource(), editor.getProject())
);
presentations.add(clickableText);
}
presentations.add(factory.textSpacePlaceholder(1, true));
Expand All @@ -135,11 +155,12 @@ private InlayPresentation toPresentation(Editor editor, int offset,
}

private void executeClientCommand(LanguageServer languageServer, CodeLens codeLens, Component source, Project project) {
if (LanguageServiceAccessor.getInstance(project).checkCapability(languageServer,
capabilites -> Boolean.TRUE.equals(capabilites.getCodeLensProvider().getResolveProvider()))) {
languageServer.getTextDocumentService().resolveCodeLens(codeLens).thenAcceptAsync(resolvedCodeLens -> {
executeClientCommand(source, resolvedCodeLens.getCommand());
});
if (LanguageServiceAccessor.getInstance(project).checkCapability(languageServer, capabilities ->
Boolean.TRUE.equals(capabilities.getCodeLensProvider().getResolveProvider()))
) {
languageServer.getTextDocumentService().resolveCodeLens(codeLens).thenAcceptAsync(resolvedCodeLens ->
executeClientCommand(source, resolvedCodeLens.getCommand())
);
} else {
executeClientCommand(source, codeLens.getCommand());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,43 +63,59 @@ public InlayHintsCollector getCollectorFor(@NotNull PsiFile psiFile,
return new FactoryInlayHintsCollector(editor) {
@Override
public boolean collect(@NotNull PsiElement psiElement, @NotNull Editor editor, @NotNull InlayHintsSink inlayHintsSink) {
Document document = editor.getDocument();
try {
URI docURI = LSPIJUtils.toUri(editor.getDocument());
if (docURI != null) {
Range viewPortRange = getViewPortRange(editor);
InlayHintParams param = new InlayHintParams(new TextDocumentIdentifier(docURI.toString()), viewPortRange);
BlockingDeque<Pair<InlayHint, LanguageServer>> pairs = new LinkedBlockingDeque<>();
List<Pair<Integer, Pair<InlayHint, LanguageServer>>> inlayhints = new ArrayList<>();
CompletableFuture<Void> future = LanguageServiceAccessor.getInstance(psiElement.getProject())
.getLanguageServers(editor.getDocument(), capabilities -> capabilities.getInlayHintProvider() != null)
.thenComposeAsync(languageServers -> CompletableFuture.allOf(languageServers.stream()
.map(languageServer -> languageServer.getSecond().getTextDocumentService().inlayHint(param)
.thenAcceptAsync(inlayHints -> {
// textDocument/codeLens may return null
if (inlayHints != null) {
inlayHints.stream().filter(Objects::nonNull)
.forEach(inlayHint -> pairs.add(new Pair(inlayHint, languageServer.getSecond())));
}
}))
.toArray(CompletableFuture[]::new)));
while (!future.isDone() || !pairs.isEmpty()) {
ProgressManager.checkCanceled();
Pair<InlayHint, LanguageServer> pair = pairs.poll(25, TimeUnit.MILLISECONDS);
if (pair != null) {
int offset = LSPIJUtils.toOffset(pair.getFirst().getPosition(), editor.getDocument());
inlayhints.add(Pair.create(offset, pair));
}
}
Map<Integer, List<Pair<Integer, Pair<InlayHint, LanguageServer>>>> elements = inlayhints.stream().collect(Collectors.groupingBy(p -> p.first));
elements.forEach((offset, list) -> inlayHintsSink.addInlineElement(offset, false,
toPresentation(editor, offset, list, getFactory()), false));
URI docURI = LSPIJUtils.toUri(document);
if (docURI == null) {
return false;
}
Range viewPortRange = getViewPortRange(editor);
InlayHintParams param = new InlayHintParams(new TextDocumentIdentifier(docURI.toString()), viewPortRange);
BlockingDeque<Pair<InlayHint, LanguageServer>> pairs = new LinkedBlockingDeque<>();
CompletableFuture<Void> future = collect(psiElement.getProject(), document, param, pairs);
List<Pair<Integer, Pair<InlayHint, LanguageServer>>> inlayHints = createInlayHints(document, pairs, future);
Map<Integer, List<Pair<Integer, Pair<InlayHint, LanguageServer>>>> elements = inlayHints.stream().collect(Collectors.groupingBy(p -> p.first));
elements.forEach((offset, list) ->
inlayHintsSink.addInlineElement(offset, false, toPresentation(editor, list, getFactory()), false));
} catch (InterruptedException e) {
LOGGER.warn(e.getLocalizedMessage(), e);
Thread.currentThread().interrupt();
}
return false;
}

@NotNull
private List<Pair<Integer, Pair<InlayHint, LanguageServer>>> createInlayHints(
@NotNull Document document,
BlockingDeque<Pair<InlayHint, LanguageServer>> pairs,
CompletableFuture<Void> future)
throws InterruptedException {
List<Pair<Integer, Pair<InlayHint, LanguageServer>>> inlayHints = new ArrayList<>();
while (!future.isDone() || !pairs.isEmpty()) {
ProgressManager.checkCanceled();
Pair<InlayHint, LanguageServer> pair = pairs.poll(25, TimeUnit.MILLISECONDS);
if (pair != null) {
int offset = LSPIJUtils.toOffset(pair.getFirst().getPosition(), document);
inlayHints.add(Pair.create(offset, pair));
}
}
return inlayHints;
}

private CompletableFuture<Void> collect(@NotNull Project project, @NotNull Document document, InlayHintParams param, BlockingDeque<Pair<InlayHint, LanguageServer>> pairs) {
return LanguageServiceAccessor.getInstance(project)
.getLanguageServers(document, capabilities -> capabilities.getInlayHintProvider() != null)
.thenComposeAsync(languageServers -> CompletableFuture.allOf(languageServers.stream()
.map(languageServer -> languageServer.getSecond().getTextDocumentService().inlayHint(param)
.thenAcceptAsync(inlayHints -> {
// textDocument/codeLens may return null
if (inlayHints != null) {
inlayHints.stream().filter(Objects::nonNull)
.forEach(inlayHint -> pairs.add(new Pair(inlayHint, languageServer.getSecond())));
}
}))
.toArray(CompletableFuture[]::new)));
}
};
}

Expand All @@ -114,7 +130,7 @@ private static Range getViewPortRange(Editor editor) {
return new Range(start, end);
}

private InlayPresentation toPresentation(Editor editor, int offset,
private InlayPresentation toPresentation(Editor editor,
List<Pair<Integer, Pair<InlayHint, LanguageServer>>> elements,
PresentationFactory factory) {
List<InlayPresentation> presentations = new ArrayList<>();
Expand All @@ -125,17 +141,7 @@ private InlayPresentation toPresentation(Editor editor, int offset,
} else {
int index = 0;
for (InlayHintLabelPart part : label.getRight()) {
InlayPresentation text = factory.smallText(part.getValue());
if (!hasCommand(part)) {
// No command, create a simple text inlay hint
presentations.add(text);
} else {
// InlayHintLabelPart defines a Command, create a clickable inlay hint
int finalIndex = index;
text = factory.referenceOnHover(text, (event, translated) -> {
executeClientCommand(p.second.second, p.second.first, finalIndex, (Component) event.getSource(), editor.getProject());
});
}
InlayPresentation text = createInlayPresentation(editor.getProject(), factory, presentations, p, index, part);
if (part.getTooltip() != null && part.getTooltip().isLeft()) {
text = factory.withTooltip(part.getTooltip().getLeft(), text);
}
Expand All @@ -147,13 +153,40 @@ private InlayPresentation toPresentation(Editor editor, int offset,
return factory.roundWithBackground(new SequencePresentation(presentations));
}

@NotNull
private InlayPresentation createInlayPresentation(
Project project,
PresentationFactory factory,
List<InlayPresentation> presentations, Pair<Integer,
Pair<InlayHint, LanguageServer>> p,
int index,
InlayHintLabelPart part) {
InlayPresentation text = factory.smallText(part.getValue());
if (!hasCommand(part)) {
// No command, create a simple text inlay hint
presentations.add(text);
} else {
// InlayHintLabelPart defines a Command, create a clickable inlay hint
int finalIndex = index;
text = factory.referenceOnHover(text, (event, translated) ->
executeClientCommand(p.second.second, p.second.first, finalIndex, (Component) event.getSource(), project)
);
}
return text;
}

private static boolean hasCommand(InlayHintLabelPart part) {
Command command = part.getCommand();
return (command != null && command.getCommand() != null && !command.getCommand().isEmpty());
}

private void executeClientCommand(LanguageServer languageServer, InlayHint inlayHint, int index, Component source,
Project project) {
private void executeClientCommand(
LanguageServer languageServer,
InlayHint inlayHint,
int index,
Component source,
Project project
) {
if (LanguageServiceAccessor.getInstance(project)
.checkCapability(languageServer, capabilites -> isResolveSupported(capabilites.getInlayHintProvider()))) {
languageServer.getTextDocumentService()
Expand Down

0 comments on commit f8890f6

Please sign in to comment.