CodeLens for boot hints in VSCode
This commit is contained in:
@@ -50,7 +50,7 @@
|
||||
"dependencies": {
|
||||
"atom-package-deps": "^4.6.0",
|
||||
"download": "^6.2.5",
|
||||
"@pivotal-tools/atom-languageclient-commons": "0.0.7"
|
||||
"@pivotal-tools/atom-languageclient-commons": "0.0.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^2.7.2",
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
"properties.json"
|
||||
],
|
||||
"dependencies": {
|
||||
"@pivotal-tools/atom-languageclient-commons": "0.0.7",
|
||||
"@pivotal-tools/atom-languageclient-commons": "0.0.8",
|
||||
"atom-package-deps": "^4.6.0",
|
||||
"download": "^6.2.5"
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {Convert} from 'atom-languageclient';
|
||||
import {AtomEnvironment, TextEditor} from 'atom';
|
||||
import {Position, Range, TextDocumentIdentifier} from 'vscode-languageserver-protocol';
|
||||
import {Position, CodeLens, TextDocumentIdentifier} from 'vscode-languageserver-protocol';
|
||||
|
||||
export class StsAdapter {
|
||||
|
||||
@@ -34,5 +34,5 @@ export interface ProgressParams {
|
||||
|
||||
export interface HighlightParams {
|
||||
readonly doc: TextDocumentIdentifier;
|
||||
readonly ranges: Range[];
|
||||
readonly codeLenses: CodeLens[];
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@pivotal-tools/atom-languageclient-commons",
|
||||
"version": "0.0.7",
|
||||
"version": "0.0.8",
|
||||
"description": "Atom language client commons for STS4 language servers",
|
||||
"repository": "https://github.com/spring-projects/sts4",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
"dependencies": {
|
||||
"atom-package-deps": "^4.6.0",
|
||||
"download": "^6.2.5",
|
||||
"@pivotal-tools/atom-languageclient-commons": "0.0.7"
|
||||
"@pivotal-tools/atom-languageclient-commons": "0.0.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^2.7.2",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {StsAdapter, HighlightParams} from '@pivotal-tools/atom-languageclient-commons';
|
||||
import {Convert} from 'atom-languageclient';
|
||||
import { Range } from 'vscode-languageserver-protocol';
|
||||
import { Range, CodeLens } from 'vscode-languageserver-protocol';
|
||||
import {TextEditor, DecorationOptions } from 'atom';
|
||||
|
||||
const BOOT_HINT_GUTTER_NAME = 'boot-hint-gutter';
|
||||
@@ -18,11 +18,12 @@ export class BootStsAdapter extends StsAdapter {
|
||||
}
|
||||
|
||||
onHighlight(params: HighlightParams) {
|
||||
this.findEditors(params.doc.uri).forEach(editor => this.markHintsForEditor(editor, params.ranges));
|
||||
this.findEditors(params.doc.uri).forEach(editor => this.markHintsForEditor(editor, params.codeLenses));
|
||||
}
|
||||
|
||||
private markHintsForEditor(editor: TextEditor, ranges: Range[]) {
|
||||
private markHintsForEditor(editor: TextEditor, codeLenses: CodeLens[]) {
|
||||
editor.getDecorations(DECORATION_OPTIONS).map(decoration => decoration.getMarker()).forEach(m => m.destroy());
|
||||
const ranges = codeLenses.map(cl => cl.range);
|
||||
if (Array.isArray(ranges)) {
|
||||
ranges.forEach(range => this.createHintMarker(editor, range));
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"atom-languageclient": "0.9.5",
|
||||
"@pivotal-tools/atom-languageclient-commons": "0.0.7",
|
||||
"@pivotal-tools/atom-languageclient-commons": "0.0.8",
|
||||
"atom-package-deps": "^4.6.0",
|
||||
"download": "^6.2.5"
|
||||
},
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
package org.springframework.tooling.ls.eclipse.commons;
|
||||
|
||||
import org.eclipse.jface.text.Position;
|
||||
import org.eclipse.jface.text.source.ISourceViewer;
|
||||
import org.eclipse.jface.text.source.inlined.LineHeaderAnnotation;
|
||||
import org.eclipse.swt.custom.StyledText;
|
||||
import org.eclipse.swt.graphics.Color;
|
||||
import org.eclipse.swt.graphics.FontMetrics;
|
||||
import org.eclipse.swt.graphics.GC;
|
||||
import org.eclipse.swt.graphics.Image;
|
||||
import org.eclipse.swt.graphics.Rectangle;
|
||||
|
||||
public class BootHeadlineAnnotation extends LineHeaderAnnotation {
|
||||
|
||||
public BootHeadlineAnnotation(Position position, ISourceViewer viewer) {
|
||||
super(position, viewer);
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public void draw(GC gc, StyledText textWidget, int offset, int length, Color color, int x, int y) {
|
||||
// initGC(textWidget, color, gc);
|
||||
//
|
||||
// FontMetrics fontMetrics = gc.getFontMetrics();
|
||||
// int height = fontMetrics.getHeight();
|
||||
//
|
||||
// Image bootImage = LanguageServerCommonsActivator.getInstance().getImageRegistry().get(LanguageServerCommonsActivator.BOOT_ICON_2X_KEY);
|
||||
// Rectangle bootImgBounds = bootImage.getBounds();
|
||||
// int width = (int) Math.round(bootImgBounds.width / (double) bootImgBounds.height * height);
|
||||
//
|
||||
// gc.drawImage(bootImage, bootImgBounds.x, bootImgBounds.y, bootImgBounds.width, bootImgBounds.height, x, y, width, height);
|
||||
//
|
||||
// int textX = x + width + 4;
|
||||
// int textY = y;
|
||||
//
|
||||
// gc.drawText("CODE LENS goes here!", textX, textY);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Initialize GC with given color and styled text background color and font.
|
||||
// *
|
||||
// * @param textWidget the text widget
|
||||
// * @param color the color
|
||||
// * @param gc the gc to initialize
|
||||
// */
|
||||
// private void initGC(StyledText textWidget, Color color, GC gc) {
|
||||
// gc.setForeground(color);
|
||||
// gc.setBackground(textWidget.getBackground());
|
||||
// gc.setFont(textWidget.getFont());
|
||||
// }
|
||||
|
||||
|
||||
}
|
||||
@@ -12,7 +12,7 @@ package org.springframework.tooling.ls.eclipse.commons;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.eclipse.lsp4j.CodeLens;
|
||||
import org.eclipse.lsp4j.VersionedTextDocumentIdentifier;
|
||||
|
||||
public class HighlightParams {
|
||||
@@ -23,15 +23,15 @@ public class HighlightParams {
|
||||
// a update site.
|
||||
|
||||
private VersionedTextDocumentIdentifier doc;
|
||||
private List<Range> ranges;
|
||||
private List<CodeLens> codeLenses;
|
||||
|
||||
public HighlightParams() {
|
||||
}
|
||||
|
||||
public HighlightParams(VersionedTextDocumentIdentifier doc, List<Range> ranges) {
|
||||
public HighlightParams(VersionedTextDocumentIdentifier doc, List<CodeLens> codeLenses) {
|
||||
super();
|
||||
this.doc = doc;
|
||||
this.ranges = ranges;
|
||||
this.codeLenses = codeLenses;
|
||||
}
|
||||
public VersionedTextDocumentIdentifier getDoc() {
|
||||
return doc;
|
||||
@@ -39,15 +39,13 @@ public class HighlightParams {
|
||||
public void setDoc(VersionedTextDocumentIdentifier doc) {
|
||||
this.doc = doc;
|
||||
}
|
||||
public List<Range> getRanges() {
|
||||
return ranges;
|
||||
}
|
||||
public void setRanges(List<Range> ranges) {
|
||||
this.ranges = ranges;
|
||||
|
||||
public List<CodeLens> getCodeLenses() {
|
||||
return codeLenses;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "HighlightParams [doc=" + doc + ", ranges=" + ranges + "]";
|
||||
public void setCodeLenses(List<CodeLens> codeLenses) {
|
||||
this.codeLenses = codeLenses;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,8 +23,11 @@ import org.eclipse.core.runtime.Status;
|
||||
import org.eclipse.jface.action.IStatusLineManager;
|
||||
import org.eclipse.jface.text.BadLocationException;
|
||||
import org.eclipse.jface.text.IDocument;
|
||||
import org.eclipse.jface.text.ITextViewerExtension2;
|
||||
import org.eclipse.jface.text.Position;
|
||||
import org.eclipse.jface.text.source.Annotation;
|
||||
import org.eclipse.jface.text.source.AnnotationPainter;
|
||||
import org.eclipse.jface.text.source.IAnnotationAccess;
|
||||
import org.eclipse.jface.text.source.IAnnotationModel;
|
||||
import org.eclipse.jface.text.source.IAnnotationModelExtension;
|
||||
import org.eclipse.jface.text.source.ISourceViewer;
|
||||
@@ -32,7 +35,7 @@ import org.eclipse.lsp4e.LSPEclipseUtils;
|
||||
import org.eclipse.lsp4e.LanguageClientImpl;
|
||||
import org.eclipse.lsp4e.LanguageServiceAccessor;
|
||||
import org.eclipse.lsp4e.LanguageServiceAccessor.LSPDocumentInfo;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.eclipse.lsp4j.CodeLens;
|
||||
import org.eclipse.lsp4j.VersionedTextDocumentIdentifier;
|
||||
import org.eclipse.ui.IEditorPart;
|
||||
import org.eclipse.ui.IEditorReference;
|
||||
@@ -137,6 +140,8 @@ public class STS4LanguageClientImpl extends LanguageClientImpl implements STS4La
|
||||
*/
|
||||
private Map<String, Annotation[]> currentAnnotations = new HashMap<>();
|
||||
|
||||
// private Map<ISourceViewer, InlinedAnnotationSupport> viewerInlinedAnnotationSupport = new WeakHashMap<>();
|
||||
|
||||
private synchronized void updateAnnotations(String target, ISourceViewer sourceViewer, IAnnotationModelExtension annotationModel) {
|
||||
if (target!=null) {
|
||||
HighlightParams highlightParams = currentHighlights.get(target);
|
||||
@@ -146,10 +151,11 @@ public class STS4LanguageClientImpl extends LanguageClientImpl implements STS4La
|
||||
if (toRemove==null) {
|
||||
toRemove = new Annotation[0];
|
||||
}
|
||||
List<Range> highlights = highlightParams == null ? null : highlightParams.getRanges();
|
||||
List<CodeLens> highlights = highlightParams == null ? null : highlightParams.getCodeLenses();
|
||||
Map<Annotation, Position> newAnnotations = createAnnotations(doc, highlights);
|
||||
annotationModel.replaceAnnotations(toRemove, newAnnotations);
|
||||
currentAnnotations.put(target, newAnnotations.keySet().toArray(new Annotation[newAnnotations.size()]));
|
||||
// updateInlinedAnnotations(sourceViewer, highlights);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -166,12 +172,75 @@ public class STS4LanguageClientImpl extends LanguageClientImpl implements STS4La
|
||||
return false;
|
||||
}
|
||||
|
||||
private Map<Annotation, Position> createAnnotations(IDocument doc, List<Range> highlights) {
|
||||
// private void updateInlinedAnnotations(final ISourceViewer sourceViewer, List<CodeLens> highlights) {
|
||||
// InlinedAnnotationSupport support = viewerInlinedAnnotationSupport.get(sourceViewer);
|
||||
// if (support == null) {
|
||||
// final InlinedAnnotationSupport inlinedSupport = new InlinedAnnotationSupport();
|
||||
// inlinedSupport.install(sourceViewer, createAnnotationPainter(sourceViewer));
|
||||
// viewerInlinedAnnotationSupport.put(sourceViewer, inlinedSupport);
|
||||
// sourceViewer.getTextWidget().addDisposeListener((e) -> {
|
||||
// inlinedSupport.uninstall();
|
||||
// viewerInlinedAnnotationSupport.remove(sourceViewer);
|
||||
// });
|
||||
// support = inlinedSupport;
|
||||
// }
|
||||
// Set<AbstractInlinedAnnotation> annotations = new HashSet<>();
|
||||
// if (highlights==null) {
|
||||
// highlights = ImmutableList.of();
|
||||
// }
|
||||
// IDocument doc = sourceViewer.getDocument();
|
||||
// final InlinedAnnotationSupport inlinedSupport = support;
|
||||
// highlights.stream().filter(hl -> hl.getCommand() != null && hl.getCommand().getTitle() != null).forEach(codeLens -> {
|
||||
// try {
|
||||
// Range rng = codeLens.getRange();
|
||||
// int start = LSPEclipseUtils.toOffset(rng.getStart(), doc);
|
||||
//
|
||||
// // "Code Lens" line header annotation
|
||||
// Position headerPos = new Position(start + 1, 1);
|
||||
// BootHeadlineAnnotation headlineAnnotation = inlinedSupport.findExistingAnnotation(headerPos);
|
||||
// if (headlineAnnotation == null) {
|
||||
// headlineAnnotation = new BootHeadlineAnnotation(headerPos, sourceViewer);
|
||||
// }
|
||||
// headlineAnnotation.setText(codeLens.getCommand().getTitle());
|
||||
// annotations.add(headlineAnnotation);
|
||||
// } catch (BadLocationException e) {
|
||||
// //ignore invalid highlights
|
||||
// }
|
||||
// });
|
||||
// highlights.forEach(codeLens -> {
|
||||
// });
|
||||
// support.updateAnnotations(annotations);
|
||||
// }
|
||||
|
||||
private static AnnotationPainter createAnnotationPainter(ISourceViewer viewer) {
|
||||
IAnnotationAccess annotationAccess = new IAnnotationAccess() {
|
||||
@Override
|
||||
public Object getType(Annotation annotation) {
|
||||
return annotation.getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMultiLine(Annotation annotation) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTemporary(Annotation annotation) {
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
AnnotationPainter painter = new AnnotationPainter(viewer, annotationAccess);
|
||||
((ITextViewerExtension2) viewer).addPainter(painter);
|
||||
return painter;
|
||||
}
|
||||
|
||||
private Map<Annotation, Position> createAnnotations(IDocument doc, List<CodeLens> highlights) {
|
||||
ImmutableMap.Builder<Annotation, Position> annotations = ImmutableMap.builder();
|
||||
if (highlights==null) {
|
||||
highlights = ImmutableList.of();
|
||||
}
|
||||
for (Range rng : highlights) {
|
||||
highlights.stream().map(CodeLens::getRange).forEach(rng -> {
|
||||
try {
|
||||
int start = LSPEclipseUtils.toOffset(rng.getStart(), doc);
|
||||
int end = LSPEclipseUtils.toOffset(rng.getEnd(), doc);
|
||||
@@ -180,7 +249,7 @@ public class STS4LanguageClientImpl extends LanguageClientImpl implements STS4La
|
||||
} catch (BadLocationException e) {
|
||||
//ignore invalid highlights
|
||||
}
|
||||
}
|
||||
});
|
||||
return annotations.build();
|
||||
}
|
||||
|
||||
|
||||
@@ -12,21 +12,21 @@ package org.springframework.ide.vscode.commons.languageserver;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.eclipse.lsp4j.CodeLens;
|
||||
import org.eclipse.lsp4j.VersionedTextDocumentIdentifier;
|
||||
|
||||
public class HighlightParams {
|
||||
|
||||
private VersionedTextDocumentIdentifier doc;
|
||||
private List<Range> ranges;
|
||||
private List<CodeLens> codeLenses;
|
||||
|
||||
public HighlightParams() {
|
||||
}
|
||||
|
||||
public HighlightParams(VersionedTextDocumentIdentifier doc, List<Range> ranges) {
|
||||
public HighlightParams(VersionedTextDocumentIdentifier doc, List<CodeLens> codeLenses) {
|
||||
super();
|
||||
this.doc = doc;
|
||||
this.ranges = ranges;
|
||||
this.codeLenses = codeLenses;
|
||||
}
|
||||
public VersionedTextDocumentIdentifier getDoc() {
|
||||
return doc;
|
||||
@@ -34,11 +34,13 @@ public class HighlightParams {
|
||||
public void setDoc(VersionedTextDocumentIdentifier doc) {
|
||||
this.doc = doc;
|
||||
}
|
||||
public List<Range> getRanges() {
|
||||
return ranges;
|
||||
|
||||
public List<CodeLens> getCodeLenses() {
|
||||
return codeLenses;
|
||||
}
|
||||
public void setRanges(List<Range> ranges) {
|
||||
this.ranges = ranges;
|
||||
|
||||
public void setCodeLenses(List<CodeLens> codeLenses) {
|
||||
this.codeLenses = codeLenses;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ package org.springframework.ide.vscode.languageserver.testharness;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.springframework.ide.vscode.languageserver.testharness.LanguageServerHarness.getDocString;
|
||||
import static org.springframework.ide.vscode.languageserver.testharness.TestAsserts.assertContains;
|
||||
import static org.springframework.ide.vscode.languageserver.testharness.TestAsserts.assertDoesNotContain;
|
||||
|
||||
@@ -31,6 +32,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
import javax.swing.text.BadLocationException;
|
||||
|
||||
import org.eclipse.lsp4j.CodeLens;
|
||||
import org.eclipse.lsp4j.CompletionItem;
|
||||
import org.eclipse.lsp4j.CompletionList;
|
||||
import org.eclipse.lsp4j.Diagnostic;
|
||||
@@ -56,8 +58,6 @@ import com.google.common.collect.ImmutableList;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import static org.springframework.ide.vscode.languageserver.testharness.LanguageServerHarness.*;
|
||||
|
||||
public class Editor {
|
||||
|
||||
public static final Predicate<CompletionItem> RELAXED_COMPLETION
|
||||
@@ -210,7 +210,7 @@ public class Editor {
|
||||
|
||||
public List<Range> assertHighlights(String... expectedHighlights) throws Exception {
|
||||
HighlightParams highlights = harness.getHighlights(doc);
|
||||
List<Range> ranges = highlights != null ? new ArrayList<>(highlights.getRanges()) : ImmutableList.of();
|
||||
List<Range> ranges = highlights != null ? highlights.getCodeLenses().stream().map(CodeLens::getRange).collect(Collectors.toList()) : ImmutableList.of();
|
||||
Collections.sort(ranges, RANGE_COMPARATOR);
|
||||
List<String> actualHighlights = ranges.stream()
|
||||
.map(this::getText)
|
||||
|
||||
@@ -145,7 +145,7 @@ public class LanguageServerHarness<S extends SimpleLanguageServerWrapper> {
|
||||
this.defaultLanguageId = defaultLanguageId;
|
||||
}
|
||||
|
||||
public static final Duration HIGHLIGHTS_TIMEOUT = Duration.ofMillis(15_000); //Why so long?
|
||||
public static final Duration HIGHLIGHTS_TIMEOUT = Duration.ofMillis(15000000000L); //Why so long?
|
||||
|
||||
public LanguageServerHarness(Callable<S> factory) throws Exception {
|
||||
this(factory, LanguageId.PLAINTEXT);
|
||||
|
||||
@@ -296,78 +296,92 @@ public class BootJavaLanguageServerComponents implements LanguageServerComponent
|
||||
RunningAppProvider runningAppProvider) {
|
||||
AnnotationHierarchyAwareLookup<HoverProvider> providers = new AnnotationHierarchyAwareLookup<>();
|
||||
|
||||
providers.put(org.springframework.ide.vscode.boot.java.value.Constants.SPRING_VALUE, new ValueHoverProvider());
|
||||
ValueHoverProvider valueHoverProvider = new ValueHoverProvider();
|
||||
RequestMappingHoverProvider requestMappingHoverProvider = new RequestMappingHoverProvider();
|
||||
AutowiredHoverProvider autowiredHoverProvider = new AutowiredHoverProvider(this);
|
||||
ComponentInjectionsHoverProvider componentInjectionsHoverProvider = new ComponentInjectionsHoverProvider(this);
|
||||
BeanInjectedIntoHoverProvider beanInjectedIntoHoverProvider = new BeanInjectedIntoHoverProvider(this);
|
||||
ConditionalsLiveHoverProvider conditionalsLiveHoverProvider = new ConditionalsLiveHoverProvider();
|
||||
|
||||
providers.put(Annotations.SPRING_REQUEST_MAPPING, new RequestMappingHoverProvider());
|
||||
providers.put(Annotations.SPRING_GET_MAPPING, new RequestMappingHoverProvider());
|
||||
providers.put(Annotations.SPRING_POST_MAPPING, new RequestMappingHoverProvider());
|
||||
providers.put(Annotations.SPRING_PUT_MAPPING, new RequestMappingHoverProvider());
|
||||
providers.put(Annotations.SPRING_DELETE_MAPPING, new RequestMappingHoverProvider());
|
||||
providers.put(Annotations.SPRING_PATCH_MAPPING, new RequestMappingHoverProvider());
|
||||
providers.put(org.springframework.ide.vscode.boot.java.value.Constants.SPRING_VALUE, valueHoverProvider);
|
||||
|
||||
providers.put(Annotations.SPRING_REQUEST_MAPPING, requestMappingHoverProvider);
|
||||
providers.put(Annotations.SPRING_GET_MAPPING, requestMappingHoverProvider);
|
||||
providers.put(Annotations.SPRING_POST_MAPPING, requestMappingHoverProvider);
|
||||
providers.put(Annotations.SPRING_PUT_MAPPING, requestMappingHoverProvider);
|
||||
providers.put(Annotations.SPRING_DELETE_MAPPING, requestMappingHoverProvider);
|
||||
providers.put(Annotations.SPRING_PATCH_MAPPING, requestMappingHoverProvider);
|
||||
providers.put(Annotations.PROFILE, new ActiveProfilesProvider());
|
||||
|
||||
providers.put(Annotations.AUTOWIRED, new AutowiredHoverProvider(this));
|
||||
providers.put(Annotations.INJECT, new AutowiredHoverProvider(this));
|
||||
providers.put(Annotations.COMPONENT, new ComponentInjectionsHoverProvider(this));
|
||||
providers.put(Annotations.BEAN, new BeanInjectedIntoHoverProvider(this));
|
||||
providers.put(Annotations.AUTOWIRED, autowiredHoverProvider);
|
||||
providers.put(Annotations.INJECT, autowiredHoverProvider);
|
||||
providers.put(Annotations.COMPONENT, componentInjectionsHoverProvider);
|
||||
providers.put(Annotations.BEAN, beanInjectedIntoHoverProvider);
|
||||
|
||||
providers.put(Annotations.CONDITIONAL, new ConditionalsLiveHoverProvider());
|
||||
providers.put(Annotations.CONDITIONAL_ON_BEAN, new ConditionalsLiveHoverProvider());
|
||||
providers.put(Annotations.CONDITIONAL_ON_MISSING_BEAN, new ConditionalsLiveHoverProvider());
|
||||
providers.put(Annotations.CONDITIONAL_ON_PROPERTY, new ConditionalsLiveHoverProvider());
|
||||
providers.put(Annotations.CONDITIONAL_ON_RESOURCE, new ConditionalsLiveHoverProvider());
|
||||
providers.put(Annotations.CONDITIONAL_ON_CLASS, new ConditionalsLiveHoverProvider());
|
||||
providers.put(Annotations.CONDITIONAL_ON_MISSING_CLASS, new ConditionalsLiveHoverProvider());
|
||||
providers.put(Annotations.CONDITIONAL_ON_CLOUD_PLATFORM, new ConditionalsLiveHoverProvider());
|
||||
providers.put(Annotations.CONDITIONAL_ON_WEB_APPLICATION, new ConditionalsLiveHoverProvider());
|
||||
providers.put(Annotations.CONDITIONAL_ON_NOT_WEB_APPLICATION, new ConditionalsLiveHoverProvider());
|
||||
providers.put(Annotations.CONDITIONAL_ON_ENABLED_INFO_CONTRIBUTOR, new ConditionalsLiveHoverProvider());
|
||||
providers.put(Annotations.CONDITIONAL_ON_ENABLED_RESOURCE_CHAIN, new ConditionalsLiveHoverProvider());
|
||||
providers.put(Annotations.CONDITIONAL_ON_ENABLED_ENDPOINT, new ConditionalsLiveHoverProvider());
|
||||
providers.put(Annotations.CONDITIONAL_ON_ENABLED_HEALTH_INDICATOR, new ConditionalsLiveHoverProvider());
|
||||
providers.put(Annotations.CONDITIONAL_ON_EXPRESSION, new ConditionalsLiveHoverProvider());
|
||||
providers.put(Annotations.CONDITIONAL_ON_JAVA, new ConditionalsLiveHoverProvider());
|
||||
providers.put(Annotations.CONDITIONAL_ON_JNDI, new ConditionalsLiveHoverProvider());
|
||||
providers.put(Annotations.CONDITIONAL_ON_SINGLE_CANDIDATE, new ConditionalsLiveHoverProvider());
|
||||
providers.put(Annotations.CONDITIONAL, conditionalsLiveHoverProvider);
|
||||
providers.put(Annotations.CONDITIONAL_ON_BEAN, conditionalsLiveHoverProvider);
|
||||
providers.put(Annotations.CONDITIONAL_ON_MISSING_BEAN, conditionalsLiveHoverProvider);
|
||||
providers.put(Annotations.CONDITIONAL_ON_PROPERTY, conditionalsLiveHoverProvider);
|
||||
providers.put(Annotations.CONDITIONAL_ON_RESOURCE, conditionalsLiveHoverProvider);
|
||||
providers.put(Annotations.CONDITIONAL_ON_CLASS, conditionalsLiveHoverProvider);
|
||||
providers.put(Annotations.CONDITIONAL_ON_MISSING_CLASS, conditionalsLiveHoverProvider);
|
||||
providers.put(Annotations.CONDITIONAL_ON_CLOUD_PLATFORM, conditionalsLiveHoverProvider);
|
||||
providers.put(Annotations.CONDITIONAL_ON_WEB_APPLICATION, conditionalsLiveHoverProvider);
|
||||
providers.put(Annotations.CONDITIONAL_ON_NOT_WEB_APPLICATION, conditionalsLiveHoverProvider);
|
||||
providers.put(Annotations.CONDITIONAL_ON_ENABLED_INFO_CONTRIBUTOR, conditionalsLiveHoverProvider);
|
||||
providers.put(Annotations.CONDITIONAL_ON_ENABLED_RESOURCE_CHAIN, conditionalsLiveHoverProvider);
|
||||
providers.put(Annotations.CONDITIONAL_ON_ENABLED_ENDPOINT, conditionalsLiveHoverProvider);
|
||||
providers.put(Annotations.CONDITIONAL_ON_ENABLED_HEALTH_INDICATOR, conditionalsLiveHoverProvider);
|
||||
providers.put(Annotations.CONDITIONAL_ON_EXPRESSION, conditionalsLiveHoverProvider);
|
||||
providers.put(Annotations.CONDITIONAL_ON_JAVA, conditionalsLiveHoverProvider);
|
||||
providers.put(Annotations.CONDITIONAL_ON_JNDI, conditionalsLiveHoverProvider);
|
||||
providers.put(Annotations.CONDITIONAL_ON_SINGLE_CANDIDATE, conditionalsLiveHoverProvider);
|
||||
|
||||
return new BootJavaHoverProvider(this, javaProjectFinder, providers, runningAppProvider);
|
||||
}
|
||||
|
||||
protected SpringIndexer createAnnotationIndexer(SimpleLanguageServer server, BootLanguageServerParams params) {
|
||||
AnnotationHierarchyAwareLookup<SymbolProvider> providers = new AnnotationHierarchyAwareLookup<>();
|
||||
providers.put(Annotations.SPRING_REQUEST_MAPPING, new RequestMappingSymbolProvider());
|
||||
providers.put(Annotations.SPRING_GET_MAPPING, new RequestMappingSymbolProvider());
|
||||
providers.put(Annotations.SPRING_POST_MAPPING, new RequestMappingSymbolProvider());
|
||||
providers.put(Annotations.SPRING_PUT_MAPPING, new RequestMappingSymbolProvider());
|
||||
providers.put(Annotations.SPRING_DELETE_MAPPING, new RequestMappingSymbolProvider());
|
||||
providers.put(Annotations.SPRING_PATCH_MAPPING, new RequestMappingSymbolProvider());
|
||||
RequestMappingSymbolProvider requestMappingSymbolProvider = new RequestMappingSymbolProvider();
|
||||
BeansSymbolProvider beansSymbolProvider = new BeansSymbolProvider();
|
||||
ComponentSymbolProvider componentSymbolProvider = new ComponentSymbolProvider();
|
||||
RestrictedDefaultSymbolProvider restrictedDefaultSymbolProvider = new RestrictedDefaultSymbolProvider();
|
||||
DataRepositorySymbolProvider dataRepositorySymbolProvider = new DataRepositorySymbolProvider();
|
||||
WebfluxRouterSymbolProvider webfluxRouterSymbolProvider = new WebfluxRouterSymbolProvider();
|
||||
|
||||
providers.put(Annotations.BEAN, new BeansSymbolProvider());
|
||||
providers.put(Annotations.COMPONENT, new ComponentSymbolProvider());
|
||||
providers.put(Annotations.SPRING_REQUEST_MAPPING, requestMappingSymbolProvider);
|
||||
providers.put(Annotations.SPRING_GET_MAPPING, requestMappingSymbolProvider);
|
||||
providers.put(Annotations.SPRING_POST_MAPPING, requestMappingSymbolProvider);
|
||||
providers.put(Annotations.SPRING_PUT_MAPPING, requestMappingSymbolProvider);
|
||||
providers.put(Annotations.SPRING_DELETE_MAPPING, requestMappingSymbolProvider);
|
||||
providers.put(Annotations.SPRING_PATCH_MAPPING, requestMappingSymbolProvider);
|
||||
|
||||
providers.put(Annotations.PROFILE, new RestrictedDefaultSymbolProvider());
|
||||
providers.put(Annotations.BEAN, beansSymbolProvider);
|
||||
providers.put(Annotations.COMPONENT, componentSymbolProvider);
|
||||
|
||||
providers.put(Annotations.CONDITIONAL, new RestrictedDefaultSymbolProvider());
|
||||
providers.put(Annotations.CONDITIONAL_ON_BEAN, new RestrictedDefaultSymbolProvider());
|
||||
providers.put(Annotations.CONDITIONAL_ON_MISSING_BEAN, new RestrictedDefaultSymbolProvider());
|
||||
providers.put(Annotations.CONDITIONAL_ON_PROPERTY, new RestrictedDefaultSymbolProvider());
|
||||
providers.put(Annotations.CONDITIONAL_ON_RESOURCE, new RestrictedDefaultSymbolProvider());
|
||||
providers.put(Annotations.CONDITIONAL_ON_CLASS, new RestrictedDefaultSymbolProvider());
|
||||
providers.put(Annotations.CONDITIONAL_ON_MISSING_CLASS, new RestrictedDefaultSymbolProvider());
|
||||
providers.put(Annotations.CONDITIONAL_ON_CLOUD_PLATFORM, new RestrictedDefaultSymbolProvider());
|
||||
providers.put(Annotations.CONDITIONAL_ON_WEB_APPLICATION, new RestrictedDefaultSymbolProvider());
|
||||
providers.put(Annotations.CONDITIONAL_ON_NOT_WEB_APPLICATION, new RestrictedDefaultSymbolProvider());
|
||||
providers.put(Annotations.CONDITIONAL_ON_ENABLED_INFO_CONTRIBUTOR, new RestrictedDefaultSymbolProvider());
|
||||
providers.put(Annotations.CONDITIONAL_ON_ENABLED_RESOURCE_CHAIN, new RestrictedDefaultSymbolProvider());
|
||||
providers.put(Annotations.CONDITIONAL_ON_ENABLED_ENDPOINT, new RestrictedDefaultSymbolProvider());
|
||||
providers.put(Annotations.CONDITIONAL_ON_ENABLED_HEALTH_INDICATOR, new RestrictedDefaultSymbolProvider());
|
||||
providers.put(Annotations.CONDITIONAL_ON_EXPRESSION, new RestrictedDefaultSymbolProvider());
|
||||
providers.put(Annotations.CONDITIONAL_ON_JAVA, new RestrictedDefaultSymbolProvider());
|
||||
providers.put(Annotations.CONDITIONAL_ON_JNDI, new RestrictedDefaultSymbolProvider());
|
||||
providers.put(Annotations.CONDITIONAL_ON_SINGLE_CANDIDATE, new RestrictedDefaultSymbolProvider());
|
||||
providers.put(Annotations.PROFILE, restrictedDefaultSymbolProvider);
|
||||
|
||||
providers.put(Annotations.REPOSITORY, new DataRepositorySymbolProvider());
|
||||
providers.put("", new WebfluxRouterSymbolProvider());
|
||||
providers.put(Annotations.CONDITIONAL, restrictedDefaultSymbolProvider);
|
||||
providers.put(Annotations.CONDITIONAL_ON_BEAN, restrictedDefaultSymbolProvider);
|
||||
providers.put(Annotations.CONDITIONAL_ON_MISSING_BEAN, restrictedDefaultSymbolProvider);
|
||||
providers.put(Annotations.CONDITIONAL_ON_PROPERTY, restrictedDefaultSymbolProvider);
|
||||
providers.put(Annotations.CONDITIONAL_ON_RESOURCE, restrictedDefaultSymbolProvider);
|
||||
providers.put(Annotations.CONDITIONAL_ON_CLASS, restrictedDefaultSymbolProvider);
|
||||
providers.put(Annotations.CONDITIONAL_ON_MISSING_CLASS, restrictedDefaultSymbolProvider);
|
||||
providers.put(Annotations.CONDITIONAL_ON_CLOUD_PLATFORM, restrictedDefaultSymbolProvider);
|
||||
providers.put(Annotations.CONDITIONAL_ON_WEB_APPLICATION, restrictedDefaultSymbolProvider);
|
||||
providers.put(Annotations.CONDITIONAL_ON_NOT_WEB_APPLICATION, restrictedDefaultSymbolProvider);
|
||||
providers.put(Annotations.CONDITIONAL_ON_ENABLED_INFO_CONTRIBUTOR, restrictedDefaultSymbolProvider);
|
||||
providers.put(Annotations.CONDITIONAL_ON_ENABLED_RESOURCE_CHAIN, restrictedDefaultSymbolProvider);
|
||||
providers.put(Annotations.CONDITIONAL_ON_ENABLED_ENDPOINT, restrictedDefaultSymbolProvider);
|
||||
providers.put(Annotations.CONDITIONAL_ON_ENABLED_HEALTH_INDICATOR, restrictedDefaultSymbolProvider);
|
||||
providers.put(Annotations.CONDITIONAL_ON_EXPRESSION, restrictedDefaultSymbolProvider);
|
||||
providers.put(Annotations.CONDITIONAL_ON_JAVA, restrictedDefaultSymbolProvider);
|
||||
providers.put(Annotations.CONDITIONAL_ON_JNDI, restrictedDefaultSymbolProvider);
|
||||
providers.put(Annotations.CONDITIONAL_ON_SINGLE_CANDIDATE, restrictedDefaultSymbolProvider);
|
||||
|
||||
providers.put(Annotations.REPOSITORY, dataRepositorySymbolProvider);
|
||||
providers.put("", webfluxRouterSymbolProvider);
|
||||
|
||||
return new SpringIndexer(server, params, providers);
|
||||
}
|
||||
|
||||
@@ -22,8 +22,11 @@ import org.eclipse.jdt.core.dom.FieldDeclaration;
|
||||
import org.eclipse.jdt.core.dom.ITypeBinding;
|
||||
import org.eclipse.jdt.core.dom.MarkerAnnotation;
|
||||
import org.eclipse.jdt.core.dom.MethodDeclaration;
|
||||
import org.eclipse.jdt.core.dom.SimpleName;
|
||||
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
|
||||
import org.eclipse.jdt.core.dom.TypeDeclaration;
|
||||
import org.eclipse.lsp4j.CodeLens;
|
||||
import org.eclipse.lsp4j.Command;
|
||||
import org.eclipse.lsp4j.Hover;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.eclipse.lsp4j.jsonrpc.messages.Either;
|
||||
@@ -65,7 +68,7 @@ public class AutowiredHoverProvider implements HoverProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Range> getLiveHoverHints(IJavaProject project, Annotation annotation, TextDocument doc, SpringBootApp[] runningApps) {
|
||||
public Collection<CodeLens> getLiveHintCodeLenses(IJavaProject project, Annotation annotation, TextDocument doc, SpringBootApp[] runningApps) {
|
||||
if (runningApps.length > 0) {
|
||||
LiveBean definedBean = getDefinedBeanForTypeDeclaration(ASTUtils.findDeclaringType(annotation));
|
||||
// Annotation is MarkerNode, parent is some field, method, variable declaration node.
|
||||
@@ -80,13 +83,32 @@ public class AutowiredHoverProvider implements HoverProvider {
|
||||
return null;
|
||||
}
|
||||
|
||||
private Collection<Range> getLiveHoverHints(IJavaProject project, ASTNode declarationNode, Range range,
|
||||
private Collection<CodeLens> getLiveHoverHints(IJavaProject project, ASTNode declarationNode, Range range,
|
||||
SpringBootApp[] runningApps, LiveBean definedBean) {
|
||||
if (declarationNode != null && definedBean != null) {
|
||||
for (SpringBootApp app : runningApps) {
|
||||
List<LiveBean> relevantBeans = getRelevantAutowiredBeans(project, declarationNode, app, definedBean);
|
||||
if (!relevantBeans.isEmpty()) {
|
||||
return ImmutableList.of(range);
|
||||
CodeLens codeLens = new CodeLens();
|
||||
codeLens.setRange(range);
|
||||
StringBuilder sb = new StringBuilder("\u21D0 ");
|
||||
if (LiveHoverUtils.doBeansFitInline(relevantBeans, MAX_INLINE_BEANS_STRING_LENGTH, INLINE_BEANS_STRING_SEPARATOR)) {
|
||||
sb.append(relevantBeans.stream().map(LiveHoverUtils::getShortDisplayType).collect(Collectors.joining(INLINE_BEANS_STRING_SEPARATOR)));
|
||||
} else {
|
||||
sb.append(relevantBeans.size());
|
||||
sb.append(" bean");
|
||||
if (relevantBeans.size() > 1) {
|
||||
sb.append("s");
|
||||
}
|
||||
}
|
||||
codeLens.setData(sb.toString());
|
||||
Command cmd = new Command();
|
||||
cmd.setTitle(sb.toString());
|
||||
cmd.setCommand("org.springframework.showHoverAtPosition");
|
||||
cmd.setArguments(ImmutableList.of(range.getStart()));
|
||||
codeLens.setCommand(cmd);
|
||||
|
||||
return ImmutableList.of(codeLens);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -100,7 +122,15 @@ public class AutowiredHoverProvider implements HoverProvider {
|
||||
LiveBean definedBean = getDefinedBeanForTypeDeclaration(ASTUtils.findDeclaringType(annotation));
|
||||
// Annotation is MarkerNode, parent is some field, method, variable declaration node.
|
||||
ASTNode declarationNode = annotation.getParent();
|
||||
return provideHover(definedBean, declarationNode, offset, doc, project, runningApps);
|
||||
Hover hover = provideHover(definedBean, declarationNode, offset, doc, project, runningApps);
|
||||
if (hover != null) {
|
||||
try {
|
||||
hover.setRange(doc.toRange(annotation.getStartPosition(), annotation.getLength()));
|
||||
} catch (BadLocationException e) {
|
||||
log.error("", e);
|
||||
}
|
||||
}
|
||||
return hover;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -266,11 +296,20 @@ public class AutowiredHoverProvider implements HoverProvider {
|
||||
@Override
|
||||
public Hover provideHover(MethodDeclaration methodDeclaration, int offset, TextDocument doc, IJavaProject project, SpringBootApp[] runningApps) {
|
||||
LiveBean definedBean = getDefinedBeanForImplicitAutowiredConstructor(methodDeclaration);
|
||||
return provideHover(definedBean, methodDeclaration, offset, doc, project, runningApps);
|
||||
Hover hover = provideHover(definedBean, methodDeclaration, offset, doc, project, runningApps);
|
||||
if (hover != null) {
|
||||
SimpleName name = methodDeclaration.getName();
|
||||
try {
|
||||
hover.setRange(doc.toRange(name.getStartPosition(), name.getLength()));
|
||||
} catch (BadLocationException e) {
|
||||
log.error("", e);
|
||||
}
|
||||
}
|
||||
return hover;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Range> getLiveHoverHints(IJavaProject project, MethodDeclaration methodDeclaration, TextDocument doc,
|
||||
public Collection<CodeLens> getLiveHintCodeLenses(IJavaProject project, MethodDeclaration methodDeclaration, TextDocument doc,
|
||||
SpringBootApp[] runningApps) {
|
||||
LiveBean definedBean = getDefinedBeanForImplicitAutowiredConstructor(methodDeclaration);
|
||||
try {
|
||||
|
||||
@@ -21,16 +21,18 @@ import org.eclipse.jdt.core.dom.IMethodBinding;
|
||||
import org.eclipse.jdt.core.dom.ITypeBinding;
|
||||
import org.eclipse.jdt.core.dom.MethodDeclaration;
|
||||
import org.eclipse.jdt.core.dom.TypeDeclaration;
|
||||
import org.eclipse.lsp4j.CodeLens;
|
||||
import org.eclipse.lsp4j.Hover;
|
||||
import org.eclipse.lsp4j.MarkedString;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.eclipse.lsp4j.jsonrpc.messages.Either;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.HoverProvider;
|
||||
import org.springframework.ide.vscode.boot.java.livehover.LiveHoverUtils;
|
||||
import org.springframework.ide.vscode.commons.boot.app.cli.LiveConditional;
|
||||
import org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.util.Log;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
@@ -42,6 +44,8 @@ import com.google.common.collect.ImmutableList;
|
||||
*/
|
||||
public class ConditionalsLiveHoverProvider implements HoverProvider {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ConditionalsLiveHoverProvider.class);
|
||||
|
||||
@Override
|
||||
public Hover provideHover(ASTNode node, Annotation annotation, ITypeBinding type, int offset,
|
||||
TextDocument doc, IJavaProject project, SpringBootApp[] runningApps) {
|
||||
@@ -49,15 +53,15 @@ public class ConditionalsLiveHoverProvider implements HoverProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Range> getLiveHoverHints(IJavaProject project, Annotation annotation, TextDocument doc, SpringBootApp[] runningApps) {
|
||||
public Collection<CodeLens> getLiveHintCodeLenses(IJavaProject project, Annotation annotation, TextDocument doc, SpringBootApp[] runningApps) {
|
||||
try {
|
||||
Optional<List<LiveConditional>> val = getMatchedLiveConditionals(annotation, runningApps);
|
||||
if (val.isPresent()) {
|
||||
Range hoverRange = doc.toRange(annotation.getStartPosition(), annotation.getLength());
|
||||
return ImmutableList.of(hoverRange);
|
||||
return ImmutableList.of(new CodeLens(hoverRange));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
log.error("", e);
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -103,7 +107,7 @@ public class ConditionalsLiveHoverProvider implements HoverProvider {
|
||||
|
||||
return hover;
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
log.error("", e);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -25,8 +25,8 @@ import org.eclipse.jdt.core.dom.NormalAnnotation;
|
||||
import org.eclipse.jdt.core.dom.SimpleName;
|
||||
import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
|
||||
import org.eclipse.jdt.core.dom.TypeDeclaration;
|
||||
import org.eclipse.lsp4j.CodeLens;
|
||||
import org.eclipse.lsp4j.Hover;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.eclipse.lsp4j.TextDocumentIdentifier;
|
||||
import org.eclipse.lsp4j.TextDocumentPositionParams;
|
||||
import org.eclipse.lsp4j.jsonrpc.messages.Either;
|
||||
@@ -90,9 +90,9 @@ public class BootJavaHoverProvider implements HoverHandler {
|
||||
return SimpleTextDocumentService.NO_HOVER;
|
||||
}
|
||||
|
||||
public Range[] getLiveHoverHints(final TextDocument document, final SpringBootApp[] runningBootApps) {
|
||||
public CodeLens[] getLiveHoverHints(final TextDocument document, final SpringBootApp[] runningBootApps) {
|
||||
return server.getCompilationUnitCache().withCompilationUnit(document, cu -> {
|
||||
Collection<Range> result = new HashSet<>();
|
||||
Collection<CodeLens> result = new HashSet<>();
|
||||
try {
|
||||
if (cu != null) {
|
||||
cu.accept(new ASTVisitor() {
|
||||
@@ -158,18 +158,18 @@ public class BootJavaHoverProvider implements HoverHandler {
|
||||
} catch (Exception e) {
|
||||
logger.error("error extracting live hint information for docURI '" + document.getUri(), e);
|
||||
}
|
||||
return result.toArray(new Range[result.size()]);
|
||||
return result.toArray(new CodeLens[result.size()]);
|
||||
});
|
||||
}
|
||||
|
||||
protected void extractLiveHintsForMethod(MethodDeclaration methodDeclaration, TextDocument doc,
|
||||
SpringBootApp[] runningApps, Collection<Range> result) {
|
||||
SpringBootApp[] runningApps, Collection<CodeLens> result) {
|
||||
Collection<HoverProvider> providers = this.hoverProviders.getAll();
|
||||
if (!providers.isEmpty()) {
|
||||
for (HoverProvider provider : providers) {
|
||||
getProject(doc).ifPresent(project -> {
|
||||
if (hasActuatorDependency(project)) {
|
||||
Collection<Range> hints = provider.getLiveHoverHints(project, methodDeclaration, doc, runningApps);
|
||||
Collection<CodeLens> hints = provider.getLiveHintCodeLenses(project, methodDeclaration, doc, runningApps);
|
||||
if (hints!=null) {
|
||||
result.addAll(hints);
|
||||
}
|
||||
@@ -182,13 +182,13 @@ public class BootJavaHoverProvider implements HoverHandler {
|
||||
}
|
||||
}
|
||||
|
||||
protected void extractLiveHintsForType(TypeDeclaration typeDeclaration, TextDocument doc, SpringBootApp[] runningApps, Collection<Range> result) {
|
||||
protected void extractLiveHintsForType(TypeDeclaration typeDeclaration, TextDocument doc, SpringBootApp[] runningApps, Collection<CodeLens> result) {
|
||||
Collection<HoverProvider> providers = this.hoverProviders.getAll();
|
||||
if (!providers.isEmpty()) {
|
||||
for (HoverProvider provider : providers) {
|
||||
getProject(doc).ifPresent(project -> {
|
||||
if (hasActuatorDependency(project)) {
|
||||
Collection<Range> hints = provider.getLiveHoverHints(project, typeDeclaration, doc, runningApps);
|
||||
Collection<CodeLens> hints = provider.getLiveHintCodeLenses(project, typeDeclaration, doc, runningApps);
|
||||
if (hints!=null) {
|
||||
result.addAll(hints);
|
||||
}
|
||||
@@ -201,14 +201,14 @@ public class BootJavaHoverProvider implements HoverHandler {
|
||||
}
|
||||
}
|
||||
|
||||
protected void extractLiveHintsForAnnotation(Annotation annotation, TextDocument doc, SpringBootApp[] runningApps, Collection<Range> result) {
|
||||
protected void extractLiveHintsForAnnotation(Annotation annotation, TextDocument doc, SpringBootApp[] runningApps, Collection<CodeLens> result) {
|
||||
ITypeBinding type = annotation.resolveTypeBinding();
|
||||
if (type != null) {
|
||||
if (runningApps.length > 0) {
|
||||
for (HoverProvider provider : this.hoverProviders.get(type)) {
|
||||
getProject(doc).ifPresent(project -> {
|
||||
if (hasActuatorDependency(project)) {
|
||||
Collection<Range> hints = provider.getLiveHoverHints(project, annotation, doc, runningApps);
|
||||
Collection<CodeLens> hints = provider.getLiveHintCodeLenses(project, annotation, doc, runningApps);
|
||||
if (hints!=null) {
|
||||
result.addAll(hints);
|
||||
}
|
||||
|
||||
@@ -17,8 +17,8 @@ import org.eclipse.jdt.core.dom.Annotation;
|
||||
import org.eclipse.jdt.core.dom.ITypeBinding;
|
||||
import org.eclipse.jdt.core.dom.MethodDeclaration;
|
||||
import org.eclipse.jdt.core.dom.TypeDeclaration;
|
||||
import org.eclipse.lsp4j.CodeLens;
|
||||
import org.eclipse.lsp4j.Hover;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
@@ -38,14 +38,16 @@ public interface HoverProvider {
|
||||
return null;
|
||||
}
|
||||
|
||||
default Collection<Range> getLiveHoverHints(IJavaProject project, Annotation annotation, TextDocument doc, SpringBootApp[] runningApps) {
|
||||
return null;
|
||||
}
|
||||
default Collection<Range> getLiveHoverHints(IJavaProject project,TypeDeclaration typeDeclaration, TextDocument doc, SpringBootApp[] runningApps) {
|
||||
return null;
|
||||
}
|
||||
default Collection<Range> getLiveHoverHints(IJavaProject project, MethodDeclaration methodDeclaration, TextDocument doc, SpringBootApp[] runningApps) {
|
||||
default Collection<CodeLens> getLiveHintCodeLenses(IJavaProject project, Annotation annotation, TextDocument doc, SpringBootApp[] runningApps) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
default Collection<CodeLens> getLiveHintCodeLenses(IJavaProject project,TypeDeclaration typeDeclaration, TextDocument doc, SpringBootApp[] runningApps) {
|
||||
return null;
|
||||
}
|
||||
|
||||
default Collection<CodeLens> getLiveHintCodeLenses(IJavaProject project, MethodDeclaration methodDeclaration, TextDocument doc, SpringBootApp[] runningApps) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.livehover;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -20,6 +21,8 @@ import java.util.stream.Stream;
|
||||
import org.eclipse.jdt.core.dom.ASTNode;
|
||||
import org.eclipse.jdt.core.dom.Annotation;
|
||||
import org.eclipse.jdt.core.dom.ITypeBinding;
|
||||
import org.eclipse.lsp4j.CodeLens;
|
||||
import org.eclipse.lsp4j.Command;
|
||||
import org.eclipse.lsp4j.Hover;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.eclipse.lsp4j.jsonrpc.messages.Either;
|
||||
@@ -50,7 +53,7 @@ public abstract class AbstractInjectedIntoHoverProvider implements HoverProvider
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Range> getLiveHoverHints(IJavaProject project, Annotation annotation, TextDocument doc, SpringBootApp[] runningApps) {
|
||||
public Collection<CodeLens> getLiveHintCodeLenses(IJavaProject project, Annotation annotation, TextDocument doc, SpringBootApp[] runningApps) {
|
||||
// Highlight if any running app contains an instance of this component
|
||||
try {
|
||||
if (runningApps.length > 0) {
|
||||
@@ -59,7 +62,8 @@ public abstract class AbstractInjectedIntoHoverProvider implements HoverProvider
|
||||
if (Stream.of(runningApps).anyMatch(app -> LiveHoverUtils.hasRelevantBeans(app, definedBean))) {
|
||||
Optional<Range> nameRange = ASTUtils.nameRange(doc, annotation);
|
||||
if (nameRange.isPresent()) {
|
||||
return ImmutableList.of(nameRange.get());
|
||||
List<CodeLens> codeLenses = assembleCodeLenses(project, runningApps, definedBean, nameRange.get());
|
||||
return codeLenses.isEmpty() ? ImmutableList.of(new CodeLens(nameRange.get())) : codeLenses;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -71,18 +75,63 @@ public abstract class AbstractInjectedIntoHoverProvider implements HoverProvider
|
||||
}
|
||||
|
||||
@Override
|
||||
public Hover provideHover(ASTNode node, Annotation annotation, ITypeBinding type, int offset,
|
||||
TextDocument doc, IJavaProject project, SpringBootApp[] runningApps) {
|
||||
public Hover provideHover(ASTNode node, Annotation annotation, ITypeBinding type, int offset, TextDocument doc,
|
||||
IJavaProject project, SpringBootApp[] runningApps) {
|
||||
if (runningApps.length > 0) {
|
||||
|
||||
LiveBean definedBean = getDefinedBean(annotation);
|
||||
if (definedBean != null) {
|
||||
return assembleHover(project, runningApps, definedBean);
|
||||
Hover hover = assembleHover(project, runningApps, definedBean);
|
||||
if (hover != null) {
|
||||
Optional<Range> nameRange = ASTUtils.nameRange(doc, annotation);
|
||||
if (nameRange.isPresent()) {
|
||||
hover.setRange(nameRange.get());
|
||||
}
|
||||
}
|
||||
return hover;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected List<CodeLens> assembleCodeLenses(IJavaProject project, SpringBootApp[] runningApps, LiveBean definedBean, Range range) {
|
||||
List<CodeLens> codeLensList = new ArrayList<>();
|
||||
for (SpringBootApp app : runningApps) {
|
||||
|
||||
List<LiveBean> relevantBeans = LiveHoverUtils.findRelevantBeans(app, definedBean);
|
||||
|
||||
if (!relevantBeans.isEmpty()) {
|
||||
List<LiveBean> injectedBeans = getRelevantInjectedIntoBeans(project, app, definedBean, relevantBeans);
|
||||
if (!injectedBeans.isEmpty()) {
|
||||
CodeLens codeLens = new CodeLens();
|
||||
codeLens.setRange(range);
|
||||
StringBuilder sb = new StringBuilder("\u21D2 ");
|
||||
if (LiveHoverUtils.doBeansFitInline(relevantBeans, MAX_INLINE_BEANS_STRING_LENGTH, INLINE_BEANS_STRING_SEPARATOR)) {
|
||||
sb.append(relevantBeans.stream().map(LiveHoverUtils::getShortDisplayType).collect(Collectors.joining(INLINE_BEANS_STRING_SEPARATOR)));
|
||||
} else {
|
||||
sb.append(relevantBeans.size());
|
||||
sb.append(" bean");
|
||||
if (relevantBeans.size() > 1) {
|
||||
sb.append("s");
|
||||
}
|
||||
}
|
||||
codeLens.setData(sb.toString());
|
||||
Command cmd = new Command();
|
||||
cmd.setTitle(sb.toString());
|
||||
cmd.setCommand("org.springframework.showHoverAtPosition");
|
||||
cmd.setArguments(ImmutableList.of(range.getStart()));
|
||||
codeLens.setCommand(cmd);
|
||||
|
||||
codeLensList.add(codeLens);
|
||||
|
||||
// Break out of the loop. Just look for the first app with injected into beans
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return codeLensList;
|
||||
}
|
||||
|
||||
protected Hover assembleHover(IJavaProject project, SpringBootApp[] runningApps, LiveBean definedBean) {
|
||||
StringBuilder hover = new StringBuilder();
|
||||
|
||||
|
||||
@@ -22,14 +22,16 @@ import org.eclipse.jdt.core.dom.ASTVisitor;
|
||||
import org.eclipse.jdt.core.dom.Annotation;
|
||||
import org.eclipse.jdt.core.dom.ITypeBinding;
|
||||
import org.eclipse.jdt.core.dom.StringLiteral;
|
||||
import org.eclipse.lsp4j.CodeLens;
|
||||
import org.eclipse.lsp4j.Hover;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.eclipse.lsp4j.jsonrpc.messages.Either;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.HoverProvider;
|
||||
import org.springframework.ide.vscode.boot.java.utils.ASTUtils;
|
||||
import org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.util.Log;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
@@ -41,6 +43,8 @@ import com.google.common.collect.ImmutableSet;
|
||||
*/
|
||||
public class ActiveProfilesProvider implements HoverProvider {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ActiveProfilesProvider.class);
|
||||
|
||||
@Override
|
||||
public Hover provideHover(
|
||||
ASTNode node,
|
||||
@@ -71,19 +75,26 @@ public class ActiveProfilesProvider implements HoverProvider {
|
||||
}
|
||||
}
|
||||
if (hasInterestingApp) {
|
||||
return new Hover(
|
||||
Hover hover = new Hover(
|
||||
ImmutableList.of(Either.forLeft(markdown.toString()))
|
||||
);
|
||||
if (hover != null) {
|
||||
Optional<Range> optional = nameRange(doc, annotation);
|
||||
if (optional.isPresent()) {
|
||||
hover.setRange(optional.get());
|
||||
}
|
||||
}
|
||||
return hover;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Range> getLiveHoverHints(IJavaProject project, Annotation annotation, TextDocument doc, SpringBootApp[] runningApps) {
|
||||
public Collection<CodeLens> getLiveHintCodeLenses(IJavaProject project, Annotation annotation, TextDocument doc, SpringBootApp[] runningApps) {
|
||||
if (runningApps.length > 0) {
|
||||
Builder<Range> ranges = ImmutableList.builder();
|
||||
nameRange(doc, annotation).ifPresent(ranges::add);
|
||||
Builder<CodeLens> codeLenses = ImmutableList.builder();
|
||||
nameRange(doc, annotation).map(CodeLens::new).ifPresent(codeLenses::add);
|
||||
|
||||
Set<String> allActiveProfiles = getAllActiveProfiles(runningApps);
|
||||
annotation.accept(new ASTVisitor() {
|
||||
@@ -91,12 +102,12 @@ public class ActiveProfilesProvider implements HoverProvider {
|
||||
public boolean visit(StringLiteral node) {
|
||||
String value = ASTUtils.getLiteralValue(node);
|
||||
if (value!=null && allActiveProfiles.contains(value)) {
|
||||
rangeOf(doc, node).ifPresent(ranges::add);
|
||||
rangeOf(doc, node).map(CodeLens::new).ifPresent(codeLenses::add);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
return ranges.build();
|
||||
return codeLenses.build();
|
||||
}
|
||||
return ImmutableList.of();
|
||||
}
|
||||
@@ -124,7 +135,7 @@ public class ActiveProfilesProvider implements HoverProvider {
|
||||
}
|
||||
return Optional.of(doc.toRange(start, end-start));
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
log.error("", e);
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,9 @@ import java.util.stream.Stream;
|
||||
import org.eclipse.jdt.core.dom.ASTNode;
|
||||
import org.eclipse.jdt.core.dom.Annotation;
|
||||
import org.eclipse.jdt.core.dom.ITypeBinding;
|
||||
import org.eclipse.jdt.core.dom.SimpleName;
|
||||
import org.eclipse.jdt.core.dom.TypeDeclaration;
|
||||
import org.eclipse.lsp4j.CodeLens;
|
||||
import org.eclipse.lsp4j.Hover;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.slf4j.Logger;
|
||||
@@ -31,6 +33,7 @@ import org.springframework.ide.vscode.boot.java.utils.ASTUtils;
|
||||
import org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp;
|
||||
import org.springframework.ide.vscode.commons.boot.app.cli.livebean.LiveBean;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.util.BadLocationException;
|
||||
import org.springframework.ide.vscode.commons.util.StringUtil;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
@@ -98,7 +101,7 @@ public class ComponentInjectionsHoverProvider extends AbstractInjectedIntoHoverP
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Range> getLiveHoverHints(IJavaProject project, TypeDeclaration typeDeclaration, TextDocument doc,
|
||||
public Collection<CodeLens> getLiveHintCodeLenses(IJavaProject project, TypeDeclaration typeDeclaration, TextDocument doc,
|
||||
SpringBootApp[] runningApps) {
|
||||
if (runningApps.length > 0 && !isComponentAnnotatedType(typeDeclaration)) {
|
||||
try {
|
||||
@@ -107,7 +110,8 @@ public class ComponentInjectionsHoverProvider extends AbstractInjectedIntoHoverP
|
||||
if (Stream.of(runningApps).anyMatch(app -> LiveHoverUtils.hasRelevantBeans(app, definedBean))) {
|
||||
Optional<Range> nameRange = Optional.of(ASTUtils.nodeRegion(doc, typeDeclaration.getName()).asRange());
|
||||
if (nameRange.isPresent()) {
|
||||
return ImmutableList.of(nameRange.get());
|
||||
List<CodeLens> codeLenses = assembleCodeLenses(project, runningApps, definedBean, nameRange.get());
|
||||
return codeLenses.isEmpty() ? ImmutableList.of(new CodeLens(nameRange.get())) : codeLenses;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -126,7 +130,16 @@ public class ComponentInjectionsHoverProvider extends AbstractInjectedIntoHoverP
|
||||
|
||||
LiveBean definedBean = getDefinedBeanForType(typeDeclaration, null);
|
||||
if (definedBean != null) {
|
||||
return assembleHover(project, runningApps, definedBean);
|
||||
Hover hover = assembleHover(project, runningApps, definedBean);
|
||||
if (hover != null) {
|
||||
SimpleName name = typeDeclaration.getName();
|
||||
try {
|
||||
hover.setRange(doc.toRange(name.getStartPosition(), name.getLength()));
|
||||
} catch (BadLocationException e) {
|
||||
LOG.error("", e);
|
||||
}
|
||||
}
|
||||
return hover;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -69,6 +69,12 @@ public class LiveHoverUtils {
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public static String getShortDisplayType(LiveBean bean) {
|
||||
String type = bean.getType(true);
|
||||
int idx = type.lastIndexOf('.');
|
||||
return idx < 0 || idx == type.length() - 1 ? type : type.substring(idx + 1);
|
||||
}
|
||||
|
||||
public static String showBeanInline(BootJavaLanguageServerComponents server, IJavaProject project, LiveBean bean) {
|
||||
String id = bean.getId();
|
||||
String type = bean.getType(true);
|
||||
|
||||
@@ -22,6 +22,7 @@ import org.eclipse.jdt.core.dom.Annotation;
|
||||
import org.eclipse.jdt.core.dom.IMethodBinding;
|
||||
import org.eclipse.jdt.core.dom.ITypeBinding;
|
||||
import org.eclipse.jdt.core.dom.MethodDeclaration;
|
||||
import org.eclipse.lsp4j.CodeLens;
|
||||
import org.eclipse.lsp4j.Hover;
|
||||
import org.eclipse.lsp4j.MarkedString;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
@@ -57,18 +58,18 @@ public class RequestMappingHoverProvider implements HoverProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Range> getLiveHoverHints(IJavaProject project, Annotation annotation, TextDocument doc, SpringBootApp[] runningApps) {
|
||||
public Collection<CodeLens> getLiveHintCodeLenses(IJavaProject project, Annotation annotation, TextDocument doc, SpringBootApp[] runningApps) {
|
||||
try {
|
||||
if (runningApps.length > 0) {
|
||||
List<Tuple2<RequestMapping, SpringBootApp>> val = getRequestMappingMethodFromRunningApp(annotation, runningApps);
|
||||
if (!val.isEmpty()) {
|
||||
Range hoverRange = doc.toRange(annotation.getStartPosition(), annotation.getLength());
|
||||
return ImmutableList.of(hoverRange);
|
||||
return ImmutableList.of(new CodeLens(hoverRange));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (BadLocationException e) {
|
||||
log.error("", e);;
|
||||
log.error("", e);
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -83,17 +84,19 @@ public class RequestMappingHoverProvider implements HoverProvider {
|
||||
|
||||
if (!val.isEmpty()) {
|
||||
addHoverContent(val, hoverContent);
|
||||
Range hoverRange = doc.toRange(annotation.getStartPosition(), annotation.getLength());
|
||||
Hover hover = new Hover();
|
||||
|
||||
hover.setContents(hoverContent);
|
||||
hover.setRange(hoverRange);
|
||||
|
||||
return hover;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
Range hoverRange = doc.toRange(annotation.getStartPosition(), annotation.getLength());
|
||||
Hover hover = new Hover();
|
||||
|
||||
hover.setContents(hoverContent);
|
||||
hover.setRange(hoverRange);
|
||||
|
||||
return hover;
|
||||
} catch (Exception e) {
|
||||
log.error("", e);;
|
||||
log.error("", e);
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -114,7 +117,7 @@ public class RequestMappingHoverProvider implements HoverProvider {
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("", e);;
|
||||
log.error("", e);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ import java.util.TimerTask;
|
||||
import java.util.concurrent.ConcurrentSkipListSet;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.eclipse.lsp4j.CodeLens;
|
||||
import org.eclipse.lsp4j.TextDocumentIdentifier;
|
||||
import org.eclipse.lsp4j.VersionedTextDocumentIdentifier;
|
||||
import org.slf4j.Logger;
|
||||
@@ -156,8 +156,8 @@ public class SpringLiveHoverWatchdog {
|
||||
if (hasCurrentRunningBootApps) {
|
||||
TextDocument doc = this.server.getTextDocumentService().get(docURI);
|
||||
if (doc != null) {
|
||||
Range[] ranges = this.hoverProvider.getLiveHoverHints(doc, runningBootApps);
|
||||
publishLiveHints(docURI, ranges);
|
||||
CodeLens[] infos = this.hoverProvider.getLiveHoverHints(doc, runningBootApps);
|
||||
publishLiveHints(docURI, infos);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -195,15 +195,15 @@ public class SpringLiveHoverWatchdog {
|
||||
}
|
||||
}
|
||||
|
||||
private void publishLiveHints(String docURI, Range[] ranges) {
|
||||
private void publishLiveHints(String docURI, CodeLens[] codeLenses) {
|
||||
int version = server.getTextDocumentService().get(docURI).getVersion();
|
||||
VersionedTextDocumentIdentifier id = new VersionedTextDocumentIdentifier(version);
|
||||
id.setUri(docURI);
|
||||
server.getClient().highlight(new HighlightParams(id, Arrays.asList(ranges)));
|
||||
server.getClient().highlight(new HighlightParams(id, Arrays.asList(codeLenses)));
|
||||
}
|
||||
|
||||
private void cleanupLiveHints(String docURI) {
|
||||
publishLiveHints(docURI, new Range[0]);
|
||||
publishLiveHints(docURI, new CodeLens[0]);
|
||||
}
|
||||
|
||||
private void cleanupResources() {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { injectable, inject } from 'inversify';
|
||||
import { NotificationType } from 'vscode-jsonrpc';
|
||||
import { TextDocumentIdentifier, Range } from 'vscode-base-languageclient/lib/base';
|
||||
import { TextDocumentIdentifier, Range, CodeLens } from 'vscode-base-languageclient/lib/base';
|
||||
import { SetDecorationParams, EditorDecorationStyle, TextEditor, DeltaDecorationParams, EditorManager } from '@theia/editor/lib/browser';
|
||||
import { ILanguageClient } from '@theia/languages/lib/common';
|
||||
import { DiffUris } from '@theia/core/lib/browser/diff-uris';
|
||||
@@ -11,17 +11,11 @@ const HIGHLIGHTS_NOTIFICATION_TYPE = new NotificationType<HighlightParams,void>(
|
||||
const BOOT_LIVE_HINTS = 'Boot-Live-Hints';
|
||||
|
||||
const INLINE_BOOT_HINT_DECORATION_STYLE = new EditorDecorationStyle('inline-boot-hint-decoration', style => {
|
||||
style.borderStyle = 'dotted';
|
||||
style.borderColor = '#32BA56';
|
||||
style.borderWidth = '1px';
|
||||
});
|
||||
|
||||
const LINE_BOOT_HINT_DECORATION_STYLE = new EditorDecorationStyle('line-boot-hint-decoration', style => {
|
||||
style.backgroundImage = 'url(../../images/boot-icon.png)';
|
||||
style.display = 'block';
|
||||
style.width = '10px';
|
||||
style.height = '1em';
|
||||
style.margin = '0 2px 0 0';
|
||||
style.backgroundColor = 'rgba(109,179,63,0.25)',
|
||||
style.borderColor = 'rgba(109,179,63,0.25)',
|
||||
style.borderSpacing = '4px',
|
||||
style.borderRadius = '4px',
|
||||
style.borderWidth = '4px'
|
||||
});
|
||||
|
||||
@injectable()
|
||||
@@ -43,13 +37,11 @@ export class HighlightService {
|
||||
const decorationParams: SetDecorationParams = {
|
||||
uri: params.doc.uri,
|
||||
kind: BOOT_LIVE_HINTS,
|
||||
newDecorations: params.ranges.map(r => {
|
||||
newDecorations: params.codeLenses.map(cl => {
|
||||
return {
|
||||
range: Range.create(r.start.line, r.start.character, r.end.line, r.end.character),
|
||||
range: Range.create(cl.range.start.line, cl.range.start.character, cl.range.end.line, cl.range.end.character),
|
||||
options: {
|
||||
inlineClassName: INLINE_BOOT_HINT_DECORATION_STYLE.className,
|
||||
glyphMarginClassName: LINE_BOOT_HINT_DECORATION_STYLE.className,
|
||||
hoverMessage: 'Ho-ho, Boot Hint!',
|
||||
isWholeLine: false
|
||||
}
|
||||
}
|
||||
@@ -80,6 +72,6 @@ export class HighlightService {
|
||||
|
||||
export interface HighlightParams {
|
||||
doc: TextDocumentIdentifier
|
||||
ranges: Range[]
|
||||
codeLenses: CodeLens[]
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@pivotal-tools/jvm-launch-utils": "0.0.11",
|
||||
"portfinder": "^0.4.0"
|
||||
"portfinder": "^0.4.0",
|
||||
"deep-equal": "^1.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "2.6.1",
|
||||
|
||||
50
vscode-extensions/commons-vscode/src/code-lens-service.ts
Normal file
50
vscode-extensions/commons-vscode/src/code-lens-service.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import * as deepEqual from 'deep-equal';
|
||||
import {
|
||||
CancellationToken,
|
||||
CodeLens,
|
||||
CodeLensProvider,
|
||||
Event,
|
||||
EventEmitter,
|
||||
ProviderResult,
|
||||
TextDocument
|
||||
} from "vscode";
|
||||
import {HighlightParams, toVSRange} from './highlight-service';
|
||||
import * as Lsp from 'vscode-languageclient';
|
||||
|
||||
export class HighlightCodeLensProvider implements CodeLensProvider {
|
||||
|
||||
private highlights : Map<string, HighlightParams> = new Map<string, HighlightParams>();
|
||||
|
||||
private _onDidChangeCodeLenses = new EventEmitter<void>();
|
||||
public get onDidChangeCodeLenses(): Event<void> {
|
||||
return this._onDidChangeCodeLenses.event;
|
||||
}
|
||||
|
||||
handle(highlghtParams: HighlightParams) {
|
||||
if (!deepEqual(this.highlights.get(highlghtParams.doc.uri), highlghtParams)) {
|
||||
this.highlights.set(highlghtParams.doc.uri, highlghtParams);
|
||||
this._onDidChangeCodeLenses.fire();
|
||||
}
|
||||
}
|
||||
|
||||
static toVSCodeLens(cl: Lsp.CodeLens): CodeLens {
|
||||
const codeLens: CodeLens = {
|
||||
range: toVSRange(cl.range),
|
||||
isResolved: true,
|
||||
command: cl.command
|
||||
};
|
||||
return codeLens;
|
||||
}
|
||||
|
||||
provideCodeLenses(document: TextDocument, token: CancellationToken): ProviderResult<CodeLens[]> {
|
||||
const activeUri = document.uri.toString();
|
||||
const activeVersion = document.version;
|
||||
const highlightParams = this.highlights.get(activeUri);
|
||||
if (highlightParams && highlightParams.doc.version === activeVersion) {
|
||||
const codeLenses = highlightParams.codeLenses || [];
|
||||
return codeLenses.filter(cl => cl.command).map(cl => HighlightCodeLensProvider.toVSCodeLens(cl));
|
||||
}
|
||||
return [];
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
import {VersionedTextDocumentIdentifier, Position, Range} from 'vscode-languageclient'
|
||||
import {VersionedTextDocumentIdentifier, MarkupContent, Position, Range, CodeLens} from 'vscode-languageclient'
|
||||
import * as VSCode from 'vscode';
|
||||
import * as path from "path";
|
||||
|
||||
function toDecoration(rng : Range) : VSCode.Range {
|
||||
export function toVSRange(rng : Range) : VSCode.Range {
|
||||
return new VSCode.Range(toPosition(rng.start), toPosition(rng.end));
|
||||
}
|
||||
|
||||
@@ -11,15 +10,15 @@ function toPosition(p : Position) : VSCode.Position {
|
||||
}
|
||||
|
||||
export interface HighlightParams {
|
||||
doc: VersionedTextDocumentIdentifier
|
||||
ranges: Range[]
|
||||
doc: VersionedTextDocumentIdentifier;
|
||||
codeLenses: CodeLens[];
|
||||
}
|
||||
|
||||
export class HighlightService {
|
||||
|
||||
DECORATION : VSCode.TextEditorDecorationType;
|
||||
|
||||
highlights : Map<String, Range[]>;
|
||||
highlights : Map<String, HighlightParams>;
|
||||
|
||||
dispose() {
|
||||
this.DECORATION.dispose();
|
||||
@@ -41,7 +40,7 @@ export class HighlightService {
|
||||
}
|
||||
|
||||
handle(params : HighlightParams) : void {
|
||||
this.highlights.set(params.doc.uri, params.ranges);
|
||||
this.highlights.set(params.doc.uri, params);
|
||||
this.refresh(params.doc);
|
||||
}
|
||||
|
||||
@@ -52,10 +51,11 @@ export class HighlightService {
|
||||
const activeVersion = editor.document.version;
|
||||
if (docId.uri === activeUri && docId.version === activeVersion) {
|
||||
//We only update highlights in the active editor for now
|
||||
let highlights : Range[] = this.highlights.get(docId.uri) || [];
|
||||
let decorations = highlights.map(hl => toDecoration(hl));
|
||||
const highlightParams: HighlightParams = this.highlights.get(docId.uri);
|
||||
const highlights: CodeLens[] = highlightParams.codeLenses || [];
|
||||
let decorations = highlights.map(hl => toVSRange(hl.range));
|
||||
editor.setDecorations(this.DECORATION, decorations);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,17 +6,17 @@ import * as FS from 'fs';
|
||||
import PortFinder = require('portfinder');
|
||||
import * as Net from 'net';
|
||||
import * as ChildProcess from 'child_process';
|
||||
import { TextDocumentIdentifier, RequestType, LanguageClient, LanguageClientOptions, SettingMonitor, ServerOptions, StreamInfo, Range } from 'vscode-languageclient';
|
||||
import { TextDocument, OutputChannel, Disposable, window } from 'vscode';
|
||||
import { TextDocumentIdentifier, RequestType, LanguageClient, LanguageClientOptions, SettingMonitor, ServerOptions, StreamInfo, Position } from 'vscode-languageclient';
|
||||
import {TextDocument, OutputChannel, Disposable, window, Event, EventEmitter} from 'vscode';
|
||||
import { Trace, NotificationType } from 'vscode-jsonrpc';
|
||||
import * as P2C from 'vscode-languageclient/lib/protocolConverter';
|
||||
import {WorkspaceEdit, Position} from 'vscode-languageserver-types';
|
||||
import {HighlightService, HighlightParams} from './highlight-service';
|
||||
import { log } from 'util';
|
||||
import { tmpdir } from 'os';
|
||||
import { JVM, findJvm, findJdk } from '@pivotal-tools/jvm-launch-utils';
|
||||
import { registerClasspathService } from './classpath';
|
||||
import { registerJavadocService } from './javadoc';
|
||||
import {HighlightCodeLensProvider} from "./code-lens-service";
|
||||
|
||||
let p2c = P2C.createConverter();
|
||||
|
||||
@@ -34,6 +34,7 @@ export interface ActivatorOptions {
|
||||
workspaceOptions: VSCode.WorkspaceConfiguration;
|
||||
checkjvm?: (context: VSCode.ExtensionContext, jvm: JVM) => any;
|
||||
preferJdk?: boolean;
|
||||
highlightCodeLensSettingKey?: string;
|
||||
}
|
||||
|
||||
type JavaOptions = {
|
||||
@@ -203,18 +204,52 @@ function setupLanguageClient(context: VSCode.ExtensionContext, createServer: Ser
|
||||
|
||||
let disposable = client.start();
|
||||
|
||||
const codeLensListanableSetting = options.highlightCodeLensSettingKey ? new ListenablePreferenceSetting<boolean>(options.highlightCodeLensSettingKey) : undefined;
|
||||
|
||||
let progressService = new ProgressService();
|
||||
let highlightService = new HighlightService();
|
||||
const codelensService = new HighlightCodeLensProvider();
|
||||
let codeLensProviderSubscription: Disposable;
|
||||
|
||||
VSCode.commands.registerCommand('org.springframework.showHoverAtPosition', (position: Position) => {
|
||||
const editor = VSCode.window.activeTextEditor;
|
||||
const vsPosition = new VSCode.Position(position.line, position.character);
|
||||
editor.selection = new VSCode.Selection(vsPosition, vsPosition);
|
||||
VSCode.commands.executeCommand('editor.action.showHover');
|
||||
});
|
||||
|
||||
context.subscriptions.push(disposable);
|
||||
context.subscriptions.push(progressService);
|
||||
context.subscriptions.push(highlightService);
|
||||
|
||||
function toggleHighlightCodeLens() {
|
||||
if (!codeLensProviderSubscription && codeLensListanableSetting.value) {
|
||||
codeLensProviderSubscription = VSCode.languages.registerCodeLensProvider(options.clientOptions.documentSelector, codelensService);
|
||||
context.subscriptions.push(codeLensProviderSubscription);
|
||||
} else if (codeLensProviderSubscription) {
|
||||
codeLensProviderSubscription.dispose();
|
||||
const idx = context.subscriptions.indexOf(codeLensProviderSubscription);
|
||||
if (idx >= 0) {
|
||||
context.subscriptions.splice(idx, 1);
|
||||
}
|
||||
codeLensProviderSubscription = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (codeLensListanableSetting) {
|
||||
toggleHighlightCodeLens();
|
||||
codeLensListanableSetting.onDidChangeValue(() => toggleHighlightCodeLens())
|
||||
}
|
||||
|
||||
return client.onReady().then(() => {
|
||||
client.onNotification(progressNotification, (params: ProgressParams) => {
|
||||
progressService.handle(params);
|
||||
});
|
||||
client.onNotification(highlightNotification, (params: HighlightParams) => {
|
||||
highlightService.handle(params);
|
||||
if (codeLensListanableSetting && codeLensListanableSetting.value) {
|
||||
codelensService.handle(params);
|
||||
}
|
||||
});
|
||||
client.onRequest(moveCursorRequest, (params: MoveCursorParams) => {
|
||||
let editors = VSCode.window.visibleTextEditors;
|
||||
@@ -278,3 +313,31 @@ class ProgressService {
|
||||
this.status = null;
|
||||
}
|
||||
}
|
||||
|
||||
export interface ListenableSetting<T> {
|
||||
value: T;
|
||||
onDidChangeValue: VSCode.Event<void>
|
||||
}
|
||||
|
||||
export class ListenablePreferenceSetting<T> implements ListenableSetting<T> {
|
||||
|
||||
private _onDidChangeValue = new EventEmitter<void>();
|
||||
|
||||
constructor(private section: string) {
|
||||
VSCode.workspace.onDidChangeConfiguration(e => {
|
||||
console.log('Settings changed! value = ' + this.value);
|
||||
if (e.affectsConfiguration(this.section)) {
|
||||
this._onDidChangeValue.fire();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
get value(): T {
|
||||
return VSCode.workspace.getConfiguration().get(this.section);
|
||||
}
|
||||
|
||||
get onDidChangeValue(): Event<void> {
|
||||
return this._onDidChangeValue.event;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,23 +1,19 @@
|
||||
'use strict';
|
||||
|
||||
import * as VSCode from 'vscode';
|
||||
import * as Path from 'path';
|
||||
import * as FS from 'fs';
|
||||
import * as Net from 'net';
|
||||
import * as ChildProcess from 'child_process';
|
||||
import {LanguageClient, LanguageClientOptions, SettingMonitor, ServerOptions, StreamInfo} from 'vscode-languageclient';
|
||||
import { workspace, TextDocument } from 'vscode';
|
||||
import {workspace} from 'vscode';
|
||||
|
||||
import * as commons from '@pivotal-tools/commons-vscode';
|
||||
|
||||
import {generate_pipeline, UserQuestioner} from '@pivotal-tools/pipeline-builder';
|
||||
import {LanguageClient} from "vscode-languageclient";
|
||||
|
||||
const PROPERTIES_LANGUAGE_ID = "spring-boot-properties";
|
||||
const YAML_LANGUAGE_ID = "spring-boot-properties-yaml";
|
||||
const JAVA_LANGUAGE_ID = "java";
|
||||
|
||||
/** Called when extension is activated */
|
||||
export function activate(context: VSCode.ExtensionContext) {
|
||||
export function activate(context: VSCode.ExtensionContext): Thenable<LanguageClient> {
|
||||
|
||||
// registerPipelineGenerator(context);
|
||||
|
||||
@@ -53,7 +49,8 @@ export function activate(context: VSCode.ExtensionContext) {
|
||||
initializationOptions: {
|
||||
workspaceFolders: workspace.workspaceFolders ? workspace.workspaceFolders.map(f => f.uri.toString()) : null
|
||||
}
|
||||
}
|
||||
},
|
||||
highlightCodeLensSettingKey: 'boot-java.highlight-codelens.on'
|
||||
};
|
||||
|
||||
return commons.activate(options, context);
|
||||
|
||||
@@ -68,6 +68,11 @@
|
||||
"default": true,
|
||||
"description": "Enable/Disable Spring running Boot application live hints decorators in Java source code"
|
||||
},
|
||||
"boot-java.highlight-codelens.on": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Enable/Disable Spring running Boot application Code Lenses"
|
||||
},
|
||||
"boot-java.change-detection.on": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
|
||||
Reference in New Issue
Block a user