Merge branch 'master' into live-hovers-v2
This commit is contained in:
@@ -70,6 +70,9 @@
|
||||
|
||||
<feature id="org.eclipse.wst.web_ui.feature" installMode="root"/>
|
||||
<feature id="org.eclipse.wst.xml_ui.feature" installMode="root"/>
|
||||
<feature id="org.eclipse.wst.server_ui.feature" installMode="root"/>
|
||||
<feature id="org.eclipse.wst.server_adapters.feature" installMode="root"/>
|
||||
|
||||
<feature id="org.eclipse.wst.json_ui.feature" installMode="root"/>
|
||||
<feature id="org.eclipse.wst.jsdt.feature" installMode="root"/>
|
||||
<feature id="org.eclipse.wst.jsdt.chromium.debug.feature" installMode="root"/>
|
||||
@@ -77,7 +80,11 @@
|
||||
<feature id="org.eclipse.jst.server_adapters.ext.feature" installMode="root"/>
|
||||
<feature id="org.eclipse.jst.server_adapters.feature" installMode="root"/>
|
||||
|
||||
<!-- <feature id="org.eclipse.wildwebdeveloper.feature" installMode="root"/> -->
|
||||
<feature id="org.eclipse.tm.terminal.feature" installMode="root"/>
|
||||
<!-- <feature id="org.eclipse.rse" installMode="root"/> -->
|
||||
<feature id="org.eclipse.tips.feature" installMode="root"/>
|
||||
|
||||
<feature id="org.eclipse.epp.mpc" installMode="root"/>
|
||||
|
||||
<feature id="org.sonatype.m2e.buildhelper.feature" installMode="root"/>
|
||||
|
||||
@@ -143,6 +143,7 @@
|
||||
|
||||
<exec executable="codesign" failonerror="true">
|
||||
<arg value="--verbose"/>
|
||||
<arg value="--force"/>
|
||||
<arg value="--keychain"/>
|
||||
<arg value="${env.KEYCHAIN}"/>
|
||||
<arg value="-s"/>
|
||||
|
||||
@@ -305,15 +305,10 @@
|
||||
<package.qualifierPrefix>e412</package.qualifierPrefix>
|
||||
</properties>
|
||||
<repositories>
|
||||
<!-- <repository>
|
||||
<repository>
|
||||
<id>2019-06</id>
|
||||
<layout>p2</layout>
|
||||
<url>https://download.eclipse.org/releases/2019-06/</url>
|
||||
</repository> -->
|
||||
<repository>
|
||||
<id>2019-06-staging</id>
|
||||
<layout>p2</layout>
|
||||
<url>https://download.eclipse.org/staging/2019-06/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>orbit</id>
|
||||
@@ -409,20 +404,10 @@
|
||||
<url>https://download.eclipse.org/staging/2019-09/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>2019-09-platform-i-builds</id>
|
||||
<id>orbit</id>
|
||||
<layout>p2</layout>
|
||||
<url>https://download.eclipse.org/eclipse/updates/4.13-I-builds/</url>
|
||||
<url>https://download.eclipse.org/tools/orbit/downloads/drops/R20190827152740/repository</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>orbit-i-build</id>
|
||||
<layout>p2</layout>
|
||||
<url>https://download.eclipse.org/tools/orbit/downloads/drops/I20190812210208/repository</url>
|
||||
</repository>
|
||||
<!-- <repository>
|
||||
<id>orbit-s-build</id>
|
||||
<layout>p2</layout>
|
||||
<url>https://download.eclipse.org/tools/orbit/downloads/drops/S20190726194335/repository</url>
|
||||
</repository> -->
|
||||
<repository>
|
||||
<id>latest-m2e</id>
|
||||
<layout>p2</layout>
|
||||
|
||||
@@ -22,7 +22,8 @@ Require-Bundle: org.eclipse.jdt.launching;bundle-version="3.8.0",
|
||||
org.apache.commons.lang3,
|
||||
org.eclipse.ui.genericeditor,
|
||||
org.eclipse.ui.editors,
|
||||
org.springsource.ide.eclipse.commons.core
|
||||
org.springsource.ide.eclipse.commons.core,
|
||||
org.eclipse.e4.ui.css.swt.theme
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Export-Package: org.springframework.tooling.ls.eclipse.commons,
|
||||
|
||||
@@ -6,4 +6,5 @@ bin.includes = META-INF/,\
|
||||
icons/,\
|
||||
lib/remark-1.0.0.jar,\
|
||||
lib/jsoup-1.9.2.jar,\
|
||||
about.html
|
||||
about.html,\
|
||||
css/
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
/* See bug 466075 about the pseudo-selector ":org-springframework-tooling-ls-eclipse-commons" */
|
||||
IEclipsePreferences#org-eclipse-ui-workbench:org-springframework-tooling-ls-eclipse-commons {
|
||||
preferences:
|
||||
'org.springframework.tooling.ls.eclipse.commons.STS4BootMarkerIndicationColor=56,84,26'
|
||||
@@ -14,6 +14,7 @@
|
||||
highlightPreferenceKey="STS4BootMarkerHighlighting"
|
||||
highlightPreferenceValue="true"
|
||||
icon="icons/boot-icon.png"
|
||||
includeOnPreferencePage="false"
|
||||
label="Boot Dynamic Info"
|
||||
overviewRulerPreferenceKey="STS4BootMarkerIndicationInOverviewRuler"
|
||||
overviewRulerPreferenceValue="false"
|
||||
@@ -117,4 +118,26 @@
|
||||
</commandParameter>
|
||||
</command>
|
||||
</extension>
|
||||
<extension
|
||||
point="org.eclipse.e4.ui.css.swt.theme">
|
||||
<stylesheet
|
||||
uri="css/e4-dark_sts4_prefstyle.css">
|
||||
<themeid
|
||||
refid="org.eclipse.e4.ui.css.theme.e4_dark">
|
||||
</themeid>
|
||||
</stylesheet>
|
||||
</extension>
|
||||
<extension
|
||||
point="org.eclipse.ui.themes">
|
||||
<colorDefinition
|
||||
categoryId="org.springsource.ide.eclipse.commons.ui"
|
||||
id="org.springframework.tooling.ls.eclipse.commons.STS4BootMarkerIndicationColor"
|
||||
isEditable="true"
|
||||
label="Live Boot Hint Color"
|
||||
value="219,236,207">
|
||||
<description>
|
||||
Running Spring Boot app live data availability hints
|
||||
</description>
|
||||
</colorDefinition>
|
||||
</extension>
|
||||
</plugin>
|
||||
|
||||
@@ -11,15 +11,14 @@
|
||||
package org.springframework.tooling.ls.eclipse.commons;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.eclipse.core.runtime.FileLocator;
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
import org.eclipse.core.runtime.Path;
|
||||
import org.eclipse.core.runtime.Platform;
|
||||
import org.eclipse.core.runtime.Status;
|
||||
import org.eclipse.jface.preference.PreferenceConverter;
|
||||
import org.eclipse.jface.resource.ColorRegistry;
|
||||
import org.eclipse.jface.resource.ImageDescriptor;
|
||||
import org.eclipse.jface.util.IPropertyChangeListener;
|
||||
import org.eclipse.jface.util.PropertyChangeEvent;
|
||||
@@ -28,7 +27,7 @@ import org.eclipse.swt.graphics.RGB;
|
||||
import org.eclipse.ui.PlatformUI;
|
||||
import org.eclipse.ui.internal.editors.text.EditorsPlugin;
|
||||
import org.eclipse.ui.plugin.AbstractUIPlugin;
|
||||
import org.eclipse.ui.progress.UIJob;
|
||||
import org.eclipse.ui.texteditor.AnnotationPreference;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.BundleContext;
|
||||
import org.springframework.tooling.ls.eclipse.commons.STS4LanguageClientImpl.UpdateHighlights;
|
||||
@@ -37,26 +36,22 @@ import org.springframework.tooling.ls.eclipse.commons.preferences.PreferenceCons
|
||||
@SuppressWarnings("restriction")
|
||||
public class LanguageServerCommonsActivator extends AbstractUIPlugin {
|
||||
|
||||
private static final String BOOT_HINT_ANNOTATION_TYPE = "org.springframework.tooling.bootinfo";
|
||||
|
||||
public static final String PLUGIN_ID = "org.springframework.tooling.ls.eclipse.commons";
|
||||
|
||||
public static final String BOOT_KEY = "boot-key";
|
||||
|
||||
private static LanguageServerCommonsActivator instance;
|
||||
|
||||
private ColorRegistry colorRegistry;
|
||||
|
||||
private final IPropertyChangeListener PROPERTY_LISTENER = new IPropertyChangeListener() {
|
||||
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent event) {
|
||||
switch (event.getProperty()) {
|
||||
case PreferenceConstants.HIGHLIGHT_RANGE_COLOR_PREFS:
|
||||
RGB prefsColor = PreferenceConverter
|
||||
.getColor(EditorsPlugin.getDefault().getPreferenceStore(), PreferenceConstants.HIGHLIGHT_RANGE_COLOR_PREFS);
|
||||
// Convert color to without alpha with background
|
||||
RGB derivedColor = convertRGBtoNonTransparent(prefsColor);
|
||||
colorRegistry.put(PreferenceConstants.HIGHLIGHT_RANGE_COLOR_PREFS, derivedColor);
|
||||
// No break - need to update highlights for the new color to take effect
|
||||
case PreferenceConstants.HIGHLIGHT_RANGE_COLOR_THEME:
|
||||
updateMarkerAnnotationPreferences();
|
||||
// Fall through to update highlights
|
||||
case PreferenceConstants.HIGHLIGHT_CODELENS_PREFS:
|
||||
new UpdateHighlights(null, true);
|
||||
break;
|
||||
@@ -66,22 +61,7 @@ public class LanguageServerCommonsActivator extends AbstractUIPlugin {
|
||||
|
||||
};
|
||||
|
||||
private static int convertColorToNonTransparent(int color, int bg, double alpha) {
|
||||
int x = (int) Math.round((color - (1 - alpha) * bg) / alpha);
|
||||
x = Math.max(0, x);
|
||||
x = Math.min(x, 0xFF);
|
||||
return x;
|
||||
}
|
||||
|
||||
private static RGB convertRGBtoNonTransparent(RGB rgb) {
|
||||
double alpha = 0.25;
|
||||
RGB bg = new RGB(0xFF, 0xFF, 0xFF); // white
|
||||
return new RGB(
|
||||
convertColorToNonTransparent(rgb.red, bg.red, alpha),
|
||||
convertColorToNonTransparent(rgb.green, bg.green, alpha),
|
||||
convertColorToNonTransparent(rgb.blue, bg.blue, alpha)
|
||||
);
|
||||
}
|
||||
private AnnotationPreference bootHintAnnotationPreference;
|
||||
|
||||
public LanguageServerCommonsActivator() {
|
||||
}
|
||||
@@ -92,29 +72,27 @@ public class LanguageServerCommonsActivator extends AbstractUIPlugin {
|
||||
super.start(context);
|
||||
getImageRegistry().put(BOOT_KEY, getImageDescriptor("icons/boot.png"));
|
||||
|
||||
UIJob uiJob = new UIJob("Setup color registry") {
|
||||
{
|
||||
setSystem(true);
|
||||
}
|
||||
getPreferenceStore().addPropertyChangeListener(PROPERTY_LISTENER);
|
||||
PlatformUI.getWorkbench().getThemeManager().addPropertyChangeListener(PROPERTY_LISTENER);
|
||||
|
||||
@Override
|
||||
public IStatus runInUIThread(IProgressMonitor arg0) {
|
||||
colorRegistry = new ColorRegistry(PlatformUI.getWorkbench().getDisplay(), true);
|
||||
RGB prefsColor = PreferenceConverter.getColor(EditorsPlugin.getDefault().getPreferenceStore(), PreferenceConstants.HIGHLIGHT_RANGE_COLOR_PREFS);
|
||||
colorRegistry.put(PreferenceConstants.HIGHLIGHT_RANGE_COLOR_PREFS, convertRGBtoNonTransparent(prefsColor));
|
||||
getPreferenceStore().addPropertyChangeListener(PROPERTY_LISTENER);
|
||||
EditorsPlugin.getDefault().getPreferenceStore().addPropertyChangeListener(PROPERTY_LISTENER);
|
||||
return Status.OK_STATUS;
|
||||
}
|
||||
};
|
||||
uiJob.schedule();
|
||||
bootHintAnnotationPreference = EditorsPlugin.getDefault().getMarkerAnnotationPreferences()
|
||||
.getAnnotationPreferences().stream().filter(Objects::nonNull)
|
||||
.filter(info -> BOOT_HINT_ANNOTATION_TYPE.equals(info.getAnnotationType())).findFirst().orElse(null);
|
||||
updateMarkerAnnotationPreferences();
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards theme colors on to marker preferences
|
||||
*/
|
||||
private void updateMarkerAnnotationPreferences() {
|
||||
RGB themeRgb = PlatformUI.getWorkbench().getThemeManager().getCurrentTheme().getColorRegistry()
|
||||
.getRGB(PreferenceConstants.HIGHLIGHT_RANGE_COLOR_THEME);
|
||||
PreferenceConverter.setValue(EditorsPlugin.getDefault().getPreferenceStore(),
|
||||
bootHintAnnotationPreference.getColorPreferenceKey(), themeRgb);
|
||||
}
|
||||
|
||||
public Color getBootHighlightRangeColor() {
|
||||
if (colorRegistry!=null) {
|
||||
return colorRegistry.get(PreferenceConstants.HIGHLIGHT_RANGE_COLOR_PREFS);
|
||||
}
|
||||
return null;
|
||||
return PlatformUI.getWorkbench().getThemeManager().getCurrentTheme().getColorRegistry().get(PreferenceConstants.HIGHLIGHT_RANGE_COLOR_THEME);
|
||||
}
|
||||
|
||||
public final static ImageDescriptor getImageDescriptor(String path) {
|
||||
@@ -132,8 +110,8 @@ public class LanguageServerCommonsActivator extends AbstractUIPlugin {
|
||||
|
||||
@Override
|
||||
public void stop(BundleContext context) throws Exception {
|
||||
EditorsPlugin.getDefault().getPreferenceStore().removePropertyChangeListener(PROPERTY_LISTENER);
|
||||
getPreferenceStore().removePropertyChangeListener(PROPERTY_LISTENER);
|
||||
PlatformUI.getWorkbench().getThemeManager().removePropertyChangeListener(PROPERTY_LISTENER);
|
||||
super.stop(context);
|
||||
}
|
||||
|
||||
@@ -148,4 +126,5 @@ public class LanguageServerCommonsActivator extends AbstractUIPlugin {
|
||||
public static void logInfo(String message) {
|
||||
instance.getLog().log(new Status(IStatus.INFO, instance.getBundle().getSymbolicName(), message));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.tooling.ls.eclipse.commons;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URI;
|
||||
@@ -42,8 +41,6 @@ import org.eclipse.jface.text.ITextViewer;
|
||||
import org.eclipse.jface.text.Position;
|
||||
import org.eclipse.jface.text.TextSelection;
|
||||
import org.eclipse.jface.text.source.Annotation;
|
||||
import org.eclipse.jface.text.source.AnnotationPainter;
|
||||
import org.eclipse.jface.text.source.AnnotationPainter.IDrawingStrategy;
|
||||
import org.eclipse.jface.text.source.IAnnotationModel;
|
||||
import org.eclipse.jface.text.source.IAnnotationModelExtension;
|
||||
import org.eclipse.jface.text.source.ISourceViewer;
|
||||
@@ -54,12 +51,6 @@ import org.eclipse.lsp4j.CodeLens;
|
||||
import org.eclipse.lsp4j.Location;
|
||||
import org.eclipse.lsp4j.MarkupContent;
|
||||
import org.eclipse.lsp4j.MarkupKind;
|
||||
import org.eclipse.swt.custom.StyledText;
|
||||
import org.eclipse.swt.graphics.Color;
|
||||
import org.eclipse.swt.graphics.Font;
|
||||
import org.eclipse.swt.graphics.GC;
|
||||
import org.eclipse.swt.graphics.Point;
|
||||
import org.eclipse.swt.graphics.Rectangle;
|
||||
import org.eclipse.swt.widgets.Display;
|
||||
import org.eclipse.ui.IEditorPart;
|
||||
import org.eclipse.ui.IEditorReference;
|
||||
@@ -68,9 +59,7 @@ import org.eclipse.ui.IWorkbenchPage;
|
||||
import org.eclipse.ui.IWorkbenchWindow;
|
||||
import org.eclipse.ui.PlatformUI;
|
||||
import org.eclipse.ui.progress.UIJob;
|
||||
import org.eclipse.ui.texteditor.AbstractDecoratedTextEditor;
|
||||
import org.eclipse.ui.texteditor.AbstractTextEditor;
|
||||
import org.eclipse.ui.texteditor.SourceViewerDecorationSupport;
|
||||
import org.springframework.ide.vscode.commons.protocol.CursorMovement;
|
||||
import org.springframework.ide.vscode.commons.protocol.HighlightParams;
|
||||
import org.springframework.ide.vscode.commons.protocol.ProgressParams;
|
||||
@@ -143,8 +132,8 @@ public class STS4LanguageClientImpl extends LanguageClientImpl implements STS4La
|
||||
|
||||
private static final String ANNOTION_TYPE_ID = "org.springframework.tooling.bootinfo";
|
||||
|
||||
private static final String ALT_ANNOTATION_DRAWING_STRATEGY_ID = "boot.hint.strategy";
|
||||
private static final String ALT_ANNOTATION_TYPE_ID = "org.springframework.tooling.bootinfoCodeLens";
|
||||
// private static final String ALT_ANNOTATION_DRAWING_STRATEGY_ID = "boot.hint.strategy";
|
||||
// private static final String ALT_ANNOTATION_TYPE_ID = "org.springframework.tooling.bootinfoCodeLens";
|
||||
|
||||
/**
|
||||
* Latest highlight request params. It is sufficient to only remember the last request per uri, because
|
||||
@@ -157,32 +146,32 @@ public class STS4LanguageClientImpl extends LanguageClientImpl implements STS4La
|
||||
*/
|
||||
private static Map<String, Annotation[]> currentAnnotations = new ConcurrentHashMap<>();
|
||||
|
||||
private static final IDrawingStrategy BOOT_RANGE_HIGHLIGHT_DRAWING_STRATEGY = new IDrawingStrategy() {
|
||||
|
||||
@Override
|
||||
public void draw(Annotation annotation, GC gc, StyledText textWidget, int offset, int length, Color color) {
|
||||
|
||||
if (gc == null) {
|
||||
textWidget.redrawRange(offset, length, true);
|
||||
} else {
|
||||
int oldAlpha = gc.getAlpha();
|
||||
Font oldFont = gc.getFont();
|
||||
|
||||
Point left= textWidget.getLocationAtOffset(offset);
|
||||
Point right = textWidget.getLocationAtOffset(offset + length);
|
||||
gc.setFont(textWidget.getFont());
|
||||
int fontHeight = gc.getFontMetrics().getHeight();
|
||||
Rectangle r = new Rectangle(left.x, left.y + textWidget.getLineHeight(offset) - fontHeight, right.x - left.x, fontHeight);
|
||||
gc.setAlpha(0x40);
|
||||
gc.setBackground(color);
|
||||
gc.fillRectangle(r);
|
||||
|
||||
gc.setAlpha(oldAlpha);
|
||||
gc.setFont(oldFont);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
// private static final IDrawingStrategy BOOT_RANGE_HIGHLIGHT_DRAWING_STRATEGY = new IDrawingStrategy() {
|
||||
//
|
||||
// @Override
|
||||
// public void draw(Annotation annotation, GC gc, StyledText textWidget, int offset, int length, Color color) {
|
||||
//
|
||||
// if (gc == null) {
|
||||
// textWidget.redrawRange(offset, length, true);
|
||||
// } else {
|
||||
// int oldAlpha = gc.getAlpha();
|
||||
// Font oldFont = gc.getFont();
|
||||
//
|
||||
// Point left= textWidget.getLocationAtOffset(offset);
|
||||
// Point right = textWidget.getLocationAtOffset(offset + length);
|
||||
// gc.setFont(textWidget.getFont());
|
||||
// int fontHeight = gc.getFontMetrics().getHeight();
|
||||
// Rectangle r = new Rectangle(left.x, left.y + textWidget.getLineHeight(offset) - fontHeight, right.x - left.x, fontHeight);
|
||||
// gc.setAlpha(0x40);
|
||||
// gc.setBackground(color);
|
||||
// gc.fillRectangle(r);
|
||||
//
|
||||
// gc.setAlpha(oldAlpha);
|
||||
// gc.setFont(oldFont);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// };
|
||||
|
||||
static class UpdateHighlights extends UIJob {
|
||||
|
||||
@@ -231,11 +220,11 @@ public class STS4LanguageClientImpl extends LanguageClientImpl implements STS4La
|
||||
|
||||
private static void updateHighlightAnnotations(IEditorPart editor, ISourceViewer sourceViewer,
|
||||
IAnnotationModel annotationModel, String docUri, boolean updateCodeMinings) {
|
||||
boolean codeLensHighlightOn = isCodeLensHighlightOn();
|
||||
// boolean codeLensHighlightOn = isCodeLensHighlightOn();
|
||||
if (annotationModel instanceof IAnnotationModelExtension) {
|
||||
if (codeLensHighlightOn) {
|
||||
addBootRangeHighlightSupport(editor, sourceViewer);
|
||||
}
|
||||
// if (codeLensHighlightOn) {
|
||||
// addBootRangeHighlightSupport(editor, sourceViewer);
|
||||
// }
|
||||
updateAnnotations(docUri, sourceViewer, (IAnnotationModelExtension) annotationModel);
|
||||
}
|
||||
if (updateCodeMinings && sourceViewer instanceof ISourceViewerExtension5) {
|
||||
@@ -255,39 +244,39 @@ public class STS4LanguageClientImpl extends LanguageClientImpl implements STS4La
|
||||
}
|
||||
}
|
||||
|
||||
private static void addBootRangeHighlightSupport(IEditorPart editor, ISourceViewer sourceViewer) {
|
||||
if (editor instanceof AbstractDecoratedTextEditor) {
|
||||
addBootRangeHighlightSupport((AbstractDecoratedTextEditor)editor, sourceViewer);
|
||||
}
|
||||
// else if () {
|
||||
// // TODO: XML multi page editor handling for highlight support of XML source editor
|
||||
// private static void addBootRangeHighlightSupport(IEditorPart editor, ISourceViewer sourceViewer) {
|
||||
// if (editor instanceof AbstractDecoratedTextEditor) {
|
||||
// addBootRangeHighlightSupport((AbstractDecoratedTextEditor)editor, sourceViewer);
|
||||
// }
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static void addBootRangeHighlightSupport(AbstractDecoratedTextEditor editor, ISourceViewer sourceViewer) {
|
||||
try {
|
||||
Field f = AbstractDecoratedTextEditor.class.getDeclaredField("fSourceViewerDecorationSupport");
|
||||
f.setAccessible(true);
|
||||
SourceViewerDecorationSupport support = (SourceViewerDecorationSupport) f.get(editor);
|
||||
f = SourceViewerDecorationSupport.class.getDeclaredField("fAnnotationPainter");
|
||||
f.setAccessible(true);
|
||||
AnnotationPainter painter = (AnnotationPainter) f.get(support);
|
||||
|
||||
f = AnnotationPainter.class.getDeclaredField("fAnnotationType2Color");
|
||||
f.setAccessible(true);
|
||||
Color highlightColor = LanguageServerCommonsActivator.getInstance().getBootHighlightRangeColor();
|
||||
if (highlightColor!=null && ((Map<Object, Color>)f.get(painter)).get(ALT_ANNOTATION_TYPE_ID) != highlightColor) {
|
||||
painter.setAnnotationTypeColor(ALT_ANNOTATION_TYPE_ID, highlightColor);
|
||||
painter.addDrawingStrategy(ALT_ANNOTATION_DRAWING_STRATEGY_ID, BOOT_RANGE_HIGHLIGHT_DRAWING_STRATEGY);
|
||||
painter.addAnnotationType(ALT_ANNOTATION_TYPE_ID, ALT_ANNOTATION_DRAWING_STRATEGY_ID);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
LanguageServerCommonsActivator.logError(e,
|
||||
"Failed to contribute alternative range highlight annotation. Switch off highlight CodeLense under STS Language Server preferences!");
|
||||
}
|
||||
}
|
||||
//// else if () {
|
||||
//// // TODO: XML multi page editor handling for highlight support of XML source editor
|
||||
//// }
|
||||
// }
|
||||
//
|
||||
// @SuppressWarnings("unchecked")
|
||||
// private static void addBootRangeHighlightSupport(AbstractDecoratedTextEditor editor, ISourceViewer sourceViewer) {
|
||||
// try {
|
||||
// Field f = AbstractDecoratedTextEditor.class.getDeclaredField("fSourceViewerDecorationSupport");
|
||||
// f.setAccessible(true);
|
||||
// SourceViewerDecorationSupport support = (SourceViewerDecorationSupport) f.get(editor);
|
||||
// f = SourceViewerDecorationSupport.class.getDeclaredField("fAnnotationPainter");
|
||||
// f.setAccessible(true);
|
||||
// AnnotationPainter painter = (AnnotationPainter) f.get(support);
|
||||
//
|
||||
// f = AnnotationPainter.class.getDeclaredField("fAnnotationType2Color");
|
||||
// f.setAccessible(true);
|
||||
// Color highlightColor = LanguageServerCommonsActivator.getInstance().getBootHighlightRangeColor();
|
||||
// if (highlightColor!=null && ((Map<Object, Color>)f.get(painter)).get(ALT_ANNOTATION_TYPE_ID) != highlightColor) {
|
||||
// painter.setAnnotationTypeColor(ALT_ANNOTATION_TYPE_ID, highlightColor);
|
||||
// painter.addDrawingStrategy(ALT_ANNOTATION_DRAWING_STRATEGY_ID, BOOT_RANGE_HIGHLIGHT_DRAWING_STRATEGY);
|
||||
// painter.addAnnotationType(ALT_ANNOTATION_TYPE_ID, ALT_ANNOTATION_DRAWING_STRATEGY_ID);
|
||||
// }
|
||||
//
|
||||
// } catch (Exception e) {
|
||||
// LanguageServerCommonsActivator.logError(e,
|
||||
// "Failed to contribute alternative range highlight annotation. Switch off highlight CodeLense under STS Language Server preferences!");
|
||||
// }
|
||||
// }
|
||||
|
||||
private static boolean isCodeLensHighlightOn() {
|
||||
IPreferenceStore store = LanguageServerCommonsActivator.getInstance().getPreferenceStore();
|
||||
@@ -302,7 +291,7 @@ public class STS4LanguageClientImpl extends LanguageClientImpl implements STS4La
|
||||
}
|
||||
HighlightParams highlightParams = currentHighlights.get(target);
|
||||
List<CodeLens> highlights = highlightParams == null ? null : highlightParams.getCodeLenses();
|
||||
String annotationType = isCodeLensHighlightOn() ? ALT_ANNOTATION_TYPE_ID : ANNOTION_TYPE_ID;
|
||||
String annotationType = /*isCodeLensHighlightOn() ? ALT_ANNOTATION_TYPE_ID :*/ ANNOTION_TYPE_ID;
|
||||
Map<Annotation, Position> newAnnotations = createAnnotations(sourceViewer.getDocument(), highlights, annotationType);
|
||||
annotationModel.replaceAnnotations(toRemove, newAnnotations);
|
||||
currentAnnotations.put(target, newAnnotations.keySet().toArray(new Annotation[newAnnotations.size()]));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2018 Pivotal, Inc.
|
||||
* Copyright (c) 2018, 2019 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
@@ -14,6 +14,8 @@ public class PreferenceConstants {
|
||||
|
||||
public static final String HIGHLIGHT_CODELENS_PREFS = "highlight.codelens";
|
||||
|
||||
public static final String HIGHLIGHT_RANGE_COLOR_PREFS = "STS4BootMarkerIndicationColor";
|
||||
public static final String HIGHLIGHT_RANGE_COLOR_THEME = "org.springframework.tooling.ls.eclipse.commons.STS4BootMarkerIndicationColor";
|
||||
|
||||
public static final String HIGHLIGHT_RANGE_COLOR_PREFERENCE = "STS4BootMarkerIndicationColor";
|
||||
|
||||
}
|
||||
|
||||
@@ -17,7 +17,8 @@ import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.eclipse.lsp4j.TextEdit;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.PlaceHolderString;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.commons.util.Assert;
|
||||
import org.springframework.ide.vscode.commons.util.BadLocationException;
|
||||
import org.springframework.ide.vscode.commons.util.text.IDocument;
|
||||
@@ -45,6 +46,8 @@ import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
* @author Kris De Volder
|
||||
*/
|
||||
public class DocumentEdits implements ProposalApplier {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(DocumentEdits.class);
|
||||
|
||||
private static final Pattern NON_WS_CHAR = Pattern.compile("\\S");
|
||||
|
||||
@@ -511,4 +514,20 @@ public class DocumentEdits implements ProposalApplier {
|
||||
final public boolean hasSnippets() {
|
||||
return hasSnippets;
|
||||
}
|
||||
|
||||
public void dropPrefix(String prefix) {
|
||||
try {
|
||||
if (edits.size() == 2 && edits.get(0) instanceof Deletion && edits.get(1) instanceof Insertion) {
|
||||
Deletion del = (Deletion) edits.get(0);
|
||||
Insertion ins = (Insertion) edits.get(1);
|
||||
String replacedText = doc.textBetween(del.start, del.end);
|
||||
if (ins.offset>=del.start && ins.offset <=del.end && replacedText.startsWith(prefix)) {
|
||||
del.start+=prefix.length();
|
||||
ins.text = ins.text.substring(prefix.length());
|
||||
}
|
||||
}
|
||||
} catch (BadLocationException e) {
|
||||
log.error("", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,5 +38,22 @@ public interface ICompletionProposal {
|
||||
default ICompletionProposal deemphasize(double howmuch) { return this; }
|
||||
|
||||
default boolean isDeprecated() { return false; }
|
||||
|
||||
|
||||
default TransformedCompletion dropLabelPrefix(int _numberOfDroppedChars) {
|
||||
String orgLabel = getLabel();
|
||||
int numberOfDroppedChars = Math.min(orgLabel.length(), _numberOfDroppedChars);
|
||||
String prefix = getLabel().substring(0, numberOfDroppedChars);
|
||||
return new TransformedCompletion(this) {
|
||||
@Override
|
||||
protected String tranformLabel(String originalLabel) {
|
||||
return originalLabel.substring(numberOfDroppedChars);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DocumentEdits transformEdit(DocumentEdits textEdit) {
|
||||
textEdit.dropPrefix(prefix);
|
||||
return textEdit;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,70 +68,6 @@ public abstract class ScoreableProposal implements ICompletionProposal {
|
||||
return deemphasizedBy > 0;
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public boolean isAutoInsertable() {
|
||||
// return !isDeemphasized();
|
||||
// }
|
||||
|
||||
// public StyledString getStyledDisplayString() {
|
||||
// StyledString result = new StyledString();
|
||||
// highlightPattern(getHighlightPattern(), getBaseDisplayString(), result);
|
||||
// return result;
|
||||
// }
|
||||
|
||||
// private void highlightPattern(String pattern, String data, StyledString result) {
|
||||
// Styler highlightStyle = CompletionFactory.HIGHLIGHT;
|
||||
// Styler plainStyle = isDeemphasized()?CompletionFactory.DEEMPHASIZE:CompletionFactory.NULL_STYLER;
|
||||
// if (isDeprecated()) {
|
||||
// highlightStyle = CompletionFactory.compose(highlightStyle, CompletionFactory.DEPRECATE);
|
||||
// plainStyle = CompletionFactory.compose(plainStyle, CompletionFactory.DEPRECATE);
|
||||
// }
|
||||
// if (StringUtils.hasText(pattern)) {
|
||||
// int dataPos = 0; int dataLen = data.length();
|
||||
// int patternPos = 0; int patternLen = pattern.length();
|
||||
//
|
||||
// while (dataPos<dataLen && patternPos<patternLen) {
|
||||
// int pChar = pattern.charAt(patternPos++);
|
||||
// int highlightPos = data.indexOf(pChar, dataPos);
|
||||
// if (dataPos<highlightPos) {
|
||||
// result.append(data.substring(dataPos, highlightPos), plainStyle);
|
||||
// }
|
||||
// result.append(data.charAt(highlightPos), highlightStyle);
|
||||
// dataPos = highlightPos+1;
|
||||
// }
|
||||
// if (dataPos<dataLen) {
|
||||
// result.append(data.substring(dataPos), plainStyle);
|
||||
// }
|
||||
// } else { //no pattern to highlight
|
||||
// result.append(data, plainStyle);
|
||||
// }
|
||||
// }
|
||||
|
||||
// protected abstract boolean isDeprecated();
|
||||
// protected abstract String getHighlightPattern();
|
||||
// protected abstract String getBaseDisplayString();
|
||||
|
||||
// @Override
|
||||
// public String getAdditionalProposalInfo() {
|
||||
// HoverInfo hoverInfo = getAdditionalProposalInfo(new NullProgressMonitor());
|
||||
// if (hoverInfo!=null) {
|
||||
// return hoverInfo.getHtml();
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
// @Override
|
||||
// public abstract HoverInfo getAdditionalProposalInfo(IProgressMonitor monitor);
|
||||
|
||||
// @Override
|
||||
// public CharSequence getPrefixCompletionText(IDocument document, int completionOffset) {
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public int getPrefixCompletionStart(IDocument document, int completionOffset) {
|
||||
// return completionOffset;
|
||||
// }
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getLabel();
|
||||
|
||||
@@ -8,12 +8,9 @@
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.commons.yaml.completion;
|
||||
package org.springframework.ide.vscode.commons.languageserver.completion;
|
||||
|
||||
import org.eclipse.lsp4j.CompletionItemKind;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.ScoreableProposal;
|
||||
import org.springframework.ide.vscode.commons.util.Renderable;
|
||||
|
||||
/**
|
||||
@@ -24,6 +21,7 @@ import org.springframework.ide.vscode.commons.util.Renderable;
|
||||
* @author Kris De Volder
|
||||
*/
|
||||
public abstract class TransformedCompletion extends ScoreableProposal {
|
||||
|
||||
protected final ICompletionProposal original;
|
||||
|
||||
private DocumentEdits transformedEdit = null;
|
||||
@@ -35,7 +33,9 @@ public abstract class TransformedCompletion extends ScoreableProposal {
|
||||
protected String tranformLabel(String originalLabel) {
|
||||
return originalLabel;
|
||||
}
|
||||
protected abstract DocumentEdits transformEdit(DocumentEdits textEdit);
|
||||
protected DocumentEdits transformEdit(DocumentEdits textEdit) {
|
||||
return textEdit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized DocumentEdits getTextEdit() {
|
||||
@@ -20,6 +20,7 @@ import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
|
||||
@@ -77,6 +78,22 @@ public class StringUtil {
|
||||
return "";
|
||||
}
|
||||
|
||||
public static String commonPrefix(Stream<CharSequence> strings) {
|
||||
CharSequence prefix = null;
|
||||
for (CharSequence string : (Iterable<CharSequence>)strings::iterator) {
|
||||
if (prefix==null) {
|
||||
prefix = string;
|
||||
} else {
|
||||
int end = 0;
|
||||
while (end<prefix.length() && end<string.length() && string.charAt(end)==prefix.charAt(end)) {
|
||||
end++;
|
||||
}
|
||||
prefix = prefix.subSequence(0, end);
|
||||
}
|
||||
}
|
||||
return prefix.toString();
|
||||
}
|
||||
|
||||
public static String camelCaseToHyphens(String value) {
|
||||
Matcher matcher = CAMEL_CASE_PATTERN.matcher(value);
|
||||
StringBuffer result = new StringBuffer();
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.ScoreableProposal;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.TransformedCompletion;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.PlaceHolderString;
|
||||
import org.springframework.ide.vscode.commons.util.CollectionUtil;
|
||||
import org.springframework.ide.vscode.commons.util.ExceptionUtil;
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.springframework.ide.vscode.commons.languageserver.completion.Document
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionEngine;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.ScoreableProposal;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.TransformedCompletion;
|
||||
import org.springframework.ide.vscode.commons.util.Assert;
|
||||
import org.springframework.ide.vscode.commons.util.Log;
|
||||
import org.springframework.ide.vscode.commons.util.Unicodes;
|
||||
|
||||
@@ -70,7 +70,7 @@ public class CommonLanguageTools {
|
||||
|
||||
public static Collection<StsValueHint> getValueHints(FuzzyMap<PropertyInfo> index, TypeUtil typeUtil, String query, String propertyName, EnumCaseMode caseMode) {
|
||||
Type type = getValueType(index, typeUtil, propertyName);
|
||||
if (TypeUtil.isSequencable(type)) {
|
||||
if (typeUtil.isSequencable(type)) {
|
||||
//It is useful to provide content assist for the values in the list when entering a list
|
||||
type = TypeUtil.getDomainType(type);
|
||||
}
|
||||
|
||||
@@ -230,6 +230,9 @@ public class SpringIndexerXML implements SpringIndexer {
|
||||
|
||||
@Override
|
||||
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
|
||||
if (dir.getFileName().toString().startsWith(".")) {
|
||||
return FileVisitResult.SKIP_SUBTREE;
|
||||
}
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
@@ -242,6 +245,7 @@ public class SpringIndexerXML implements SpringIndexer {
|
||||
for (PathMatcher matcher : matchers) {
|
||||
if (matcher.matches(parent)) {
|
||||
builder.add(file.toAbsolutePath().toString());
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,9 +145,9 @@ public class PropertyInfo {
|
||||
|
||||
public HintProvider getHints(TypeUtil typeUtil) {
|
||||
Type type = TypeParser.parse(this.type);
|
||||
if (TypeUtil.isMap(type)) {
|
||||
if (typeUtil.isMap(type)) {
|
||||
return HintProviders.forMap(keyHints(typeUtil), valueHints(typeUtil), TypeUtil.getDomainType(type));
|
||||
} else if (TypeUtil.isSequencable(type)) {
|
||||
} else if (typeUtil.isSequencable(type)) {
|
||||
return HintProviders.forAllValueContexts(valueHints(typeUtil));
|
||||
} else {
|
||||
return HintProviders.forHere(valueHints(typeUtil));
|
||||
|
||||
@@ -99,6 +99,9 @@ public class TypeUtil {
|
||||
|
||||
private static final Object OBJECT_TYPE_NAME = Object.class.getName();
|
||||
private static final String STRING_TYPE_NAME = String.class.getName();
|
||||
private static final String MAP_TYPE_NAME = Map.class.getName();
|
||||
private static final String SET_TYPE_NAME = Set.class.getName();
|
||||
private static final String LIST_TYPE_NAME = List.class.getName();
|
||||
private static final String INET_ADDRESS_TYPE_NAME = InetAddress.class.getName();
|
||||
private static final String DURATION_TYPE_NAME = Duration.class.getName();
|
||||
private static final String CLASS_TYPE_NAME = Class.class.getName();
|
||||
@@ -443,7 +446,7 @@ public class TypeUtil {
|
||||
* use the notation <name>[<index>]=<value> in property file
|
||||
* for properties of this type.
|
||||
*/
|
||||
public static boolean isBracketable(Type type) {
|
||||
public boolean isBracketable(Type type) {
|
||||
//Note array types where once not considered 'Bracketable'
|
||||
//see: STS-4031
|
||||
|
||||
@@ -452,32 +455,13 @@ public class TypeUtil {
|
||||
//This is actually more logical too.
|
||||
//So '[' notation in props file can be used for either list or arrays (at least in recent versions of boot).
|
||||
//Note also 'Set' are now considered bracketable. See: https://www.pivotaltracker.com/story/show/154644992
|
||||
return isArray(type) || isCollection(List.class, type) || isCollection(Set.class, type);
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private static boolean isCollection( Class<? extends Collection> klass, Type type) {
|
||||
//Note: to be really correct we should use JDT infrastructure to resolve
|
||||
//type in project classpath instead of using Java reflection.
|
||||
//However, use reflection here is okay assuming types we care about
|
||||
//are part of JRE standard libraries. Using eclipse 'type hirearchy' would
|
||||
//also potentialy be very slow.
|
||||
if (type!=null) {
|
||||
String erasure = type.getErasure();
|
||||
try {
|
||||
Class<?> erasureClass = Class.forName(erasure);
|
||||
return klass.isAssignableFrom(erasureClass);
|
||||
} catch (Exception e) {
|
||||
//type not resolveable assume its not 'array like'
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return isArray(type) || isCollection(LIST_TYPE_NAME, type) || isCollection(SET_TYPE_NAME, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if type can be treated / represented as a sequence node in .yml file
|
||||
*/
|
||||
public static boolean isSequencable(Type type) {
|
||||
public boolean isSequencable(Type type) {
|
||||
return isBracketable(type);
|
||||
}
|
||||
|
||||
@@ -485,17 +469,16 @@ public class TypeUtil {
|
||||
return type!=null && type.getErasure().endsWith("[]");
|
||||
}
|
||||
|
||||
public static boolean isMap(Type type) {
|
||||
//Note: to be really correct we should use JDT infrastructure to resolve
|
||||
//type in project classpath instead of using Java reflection.
|
||||
//However, use reflection here is okay assuming types we care about
|
||||
//are part of JRE standard libraries. Using eclipse 'type hirearchy' would
|
||||
//also potentialy be very slow.
|
||||
public boolean isMap(Type type) {
|
||||
if (type!=null) {
|
||||
String erasure = type.getErasure();
|
||||
if (MAP_TYPE_NAME.equals(erasure)) {
|
||||
//quick / easy case. No looking for types and hierarchies required.
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
Class<?> erasureClass = Class.forName(erasure);
|
||||
return Map.class.isAssignableFrom(erasureClass);
|
||||
IType erasureType = findType(erasure);
|
||||
return isAssignableFrom(MAP_TYPE_NAME, erasureType);
|
||||
} catch (Exception e) {
|
||||
//type not resolveable
|
||||
}
|
||||
@@ -503,6 +486,54 @@ public class TypeUtil {
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isCollection(String collectionTypeName, Type type) {
|
||||
if (type!=null) {
|
||||
String erasure = type.getErasure();
|
||||
if (collectionTypeName.equals(erasure)) {
|
||||
//quick / easy case. No looking for types and hierarchies required.
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
IType erasureType = findType(erasure);
|
||||
return isAssignableFrom(collectionTypeName, erasureType);
|
||||
} catch (Exception e) {
|
||||
//type not resolveable
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private boolean isAssignableFrom(String superTypeName, IType erasureType) {
|
||||
Set<String> seen = new HashSet<>();
|
||||
return searchSuperTypes(seen, erasureType, superTypeName);
|
||||
}
|
||||
|
||||
|
||||
private boolean searchSuperTypes(Set<String> seen, IType searchIn, String fqTargetType) {
|
||||
if (searchIn!=null) {
|
||||
String fqName = searchIn.getFullyQualifiedName();
|
||||
if (fqName.equals(fqTargetType)) {
|
||||
return true;
|
||||
}
|
||||
if (seen.add(fqName)) {
|
||||
for (String itfName : searchIn.getSuperInterfaceNames()) {
|
||||
IType itf = findType(itfName);
|
||||
if (searchSuperTypes(seen, itf, fqTargetType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
String klassName = searchIn.getSuperclassName();
|
||||
IType klass = findType(klassName);
|
||||
if (searchSuperTypes(seen, klass, fqTargetType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get domain type for a map or list generic type.
|
||||
*/
|
||||
@@ -966,9 +997,9 @@ public class TypeUtil {
|
||||
* List<List<List<String>>> -> 2
|
||||
* Map<*,List<String>> -> 2
|
||||
*/
|
||||
public static int getDimensionality(Type type) {
|
||||
public int getDimensionality(Type type) {
|
||||
int dim = 0;
|
||||
while (isSequencable(type) || isMap(type)) {
|
||||
while (isSequencable(type) || this.isMap(type)) {
|
||||
dim++;
|
||||
type = getDomainType(type);
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -41,12 +42,15 @@ import org.springframework.ide.vscode.boot.properties.reconcile.PropertyNavigato
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.LazyProposalApplier;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.TransformedCompletion;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.PrefixFinder;
|
||||
import org.springframework.ide.vscode.commons.util.BadLocationException;
|
||||
import org.springframework.ide.vscode.commons.util.CollectionUtil;
|
||||
import org.springframework.ide.vscode.commons.util.FuzzyMap;
|
||||
import org.springframework.ide.vscode.commons.util.FuzzyMap.Match;
|
||||
import org.springframework.ide.vscode.commons.util.FuzzyMatcher;
|
||||
import org.springframework.ide.vscode.commons.util.Streams;
|
||||
import org.springframework.ide.vscode.commons.util.StringUtil;
|
||||
import org.springframework.ide.vscode.commons.util.text.DocumentRegion;
|
||||
import org.springframework.ide.vscode.commons.util.text.IDocument;
|
||||
import org.springframework.ide.vscode.java.properties.antlr.parser.AntlrParser;
|
||||
@@ -264,7 +268,7 @@ public class PropertiesCompletionProposalsCalculator {
|
||||
if (type!=null) {
|
||||
if (typeUtil.isAssignableType(type)) {
|
||||
postfix = "=";
|
||||
} else if (TypeUtil.isBracketable(type)) {
|
||||
} else if (typeUtil.isBracketable(type)) {
|
||||
postfix = "[";
|
||||
} else if (typeUtil.isDotable(type)) {
|
||||
postfix = ".";
|
||||
@@ -359,10 +363,23 @@ public class PropertiesCompletionProposalsCalculator {
|
||||
log.error("{}", e);
|
||||
}
|
||||
});
|
||||
return proposals;
|
||||
return elideCommonPrefix(prefix, proposals);
|
||||
}
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private Collection<ICompletionProposal> elideCommonPrefix(String basePrefix, ArrayList<ICompletionProposal> proposals) {
|
||||
String prefix = StringUtil.commonPrefix(Stream.concat(Stream.of(basePrefix), proposals.stream().map(ICompletionProposal::getLabel)));
|
||||
int lastDot = prefix.lastIndexOf('.');
|
||||
if (lastDot>=0) {
|
||||
for (int i = 0; i < proposals.size(); i++) {
|
||||
ICompletionProposal p = proposals.get(i);
|
||||
proposals.set(i, p.dropLabelPrefix(lastDot+1));
|
||||
}
|
||||
}
|
||||
return proposals;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -77,22 +77,23 @@ class PropertiesHoverCalculator {
|
||||
if (valueRegion.getStart() <= propertyFinder.offset && propertyFinder.offset < valueRegion.getEnd()) {
|
||||
String valueString = valueRegion.toString();
|
||||
String propertyName = value.getParent().getKey().decode();
|
||||
Type type = getValueType(propertyFinder.index, propertyFinder.typeUtil, propertyName);
|
||||
if (TypeUtil.isSequencable(type)) {
|
||||
TypeUtil typeUtil = propertyFinder.typeUtil;
|
||||
Type type = getValueType(propertyFinder.index, typeUtil, propertyName);
|
||||
if (typeUtil.isSequencable(type)) {
|
||||
//It is useful to provide content assist for the values in the list when entering a list
|
||||
type = TypeUtil.getDomainType(type);
|
||||
}
|
||||
if (TypeUtil.isClass(type)) {
|
||||
//Special case. We want to provide hoverinfos more liberally than what's suggested for completions (i.e. even class names
|
||||
//that are not suggested by the hints because they do not meet subtyping constraints should be hoverable and linkable!
|
||||
StsValueHint hint = StsValueHint.className(valueString, propertyFinder.typeUtil);
|
||||
StsValueHint hint = StsValueHint.className(valueString, typeUtil);
|
||||
if (hint!=null) {
|
||||
return Tuples.of(createRenderable(hint), valueRegion.asRegion());
|
||||
}
|
||||
}
|
||||
//Hack: pretend to invoke content-assist at the end of the value text. This should provide hints applicable to that value
|
||||
// then show hoverinfo based on that. That way we can avoid duplication a lot of similar logic to compute hoverinfos and hyperlinks.
|
||||
Collection<StsValueHint> hints = getValueHints(propertyFinder.index, propertyFinder.typeUtil, valueString, propertyName, EnumCaseMode.ALIASED);
|
||||
Collection<StsValueHint> hints = getValueHints(propertyFinder.index, typeUtil, valueString, propertyName, EnumCaseMode.ALIASED);
|
||||
if (hints!=null) {
|
||||
Optional<StsValueHint> hint = hints.stream().filter(h -> valueString.equals(h.getValue())).findFirst();
|
||||
if (hint.isPresent()) {
|
||||
|
||||
@@ -11,16 +11,16 @@
|
||||
|
||||
package org.springframework.ide.vscode.boot.properties.reconcile;
|
||||
|
||||
import static org.springframework.ide.vscode.boot.metadata.types.TypeUtil.isBracketable;
|
||||
import static org.springframework.ide.vscode.boot.properties.reconcile.SpringPropertyProblem.problem;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.ide.vscode.boot.metadata.types.Type;
|
||||
import org.springframework.ide.vscode.boot.metadata.types.TypeUtil;
|
||||
import org.springframework.ide.vscode.boot.metadata.types.TypedProperty;
|
||||
import org.springframework.ide.vscode.boot.metadata.types.TypeUtil.BeanPropertyNameMode;
|
||||
import org.springframework.ide.vscode.boot.metadata.types.TypeUtil.EnumCaseMode;
|
||||
import org.springframework.ide.vscode.boot.metadata.types.TypedProperty;
|
||||
import org.springframework.ide.vscode.boot.properties.completions.SpringPropertiesCompletionEngine;
|
||||
import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
|
||||
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblem;
|
||||
import org.springframework.ide.vscode.commons.util.BadLocationException;
|
||||
@@ -87,7 +87,7 @@ public class PropertyNavigator {
|
||||
offset, region.getEnd()-offset));
|
||||
}
|
||||
} else if (navOp=='[') {
|
||||
if (isBracketable(type)) {
|
||||
if (typeUtil.isBracketable(type)) {
|
||||
return bracketNavigate(offset, type);
|
||||
} else {
|
||||
problemCollector.accept(problem(ApplicationPropertiesProblemType.PROP_INVALID_INDEXED_NAVIGATION,
|
||||
@@ -163,7 +163,7 @@ public class PropertyNavigator {
|
||||
* checked to be 'dotable'.
|
||||
*/
|
||||
private Type dotNavigate(int offset, Type type) {
|
||||
if (TypeUtil.isMap(type)) {
|
||||
if (typeUtil.isMap(type)) {
|
||||
int keyStart = offset+1;
|
||||
Type domainType = TypeUtil.getDomainType(type);
|
||||
int keyEnd = -1;
|
||||
|
||||
@@ -116,10 +116,10 @@ public abstract class ApplicationYamlAssistContext extends AbstractYamlAssistCon
|
||||
protected String appendTextFor(Type type) {
|
||||
//Note that proper indentation after each \n" is added automatically
|
||||
//so the strings created here do not need to contain indentation spaces
|
||||
if (TypeUtil.isMap(type)) {
|
||||
if (typeUtil.isMap(type)) {
|
||||
//ready to enter nested map key on next line
|
||||
return "\n"+YamlIndentUtil.INDENT_STR;
|
||||
} if (TypeUtil.isSequencable(type)) {
|
||||
} if (typeUtil.isSequencable(type)) {
|
||||
//ready to enter sequence element on next line
|
||||
return "\n- ";
|
||||
} else if (typeUtil.isAtomic(type)) {
|
||||
@@ -328,7 +328,7 @@ public abstract class ApplicationYamlAssistContext extends AbstractYamlAssistCon
|
||||
@Override
|
||||
public YamlAssistContext traverse(YamlPathSegment s) {
|
||||
if (s.getType()==YamlPathSegmentType.VAL_AT_KEY) {
|
||||
if (TypeUtil.isSequencable(type) || TypeUtil.isMap(type)) {
|
||||
if (typeUtil.isSequencable(type) || typeUtil.isMap(type)) {
|
||||
return contextWith(s, TypeUtil.getDomainType(type));
|
||||
}
|
||||
String key = s.toPropString();
|
||||
@@ -337,7 +337,7 @@ public abstract class ApplicationYamlAssistContext extends AbstractYamlAssistCon
|
||||
return contextWith(s, TypedProperty.typeOf(subproperties.get(key)));
|
||||
}
|
||||
} else if (s.getType()==YamlPathSegmentType.VAL_AT_INDEX) {
|
||||
if (TypeUtil.isSequencable(type)) {
|
||||
if (typeUtil.isSequencable(type)) {
|
||||
return contextWith(s, TypeUtil.getDomainType(type));
|
||||
}
|
||||
}
|
||||
@@ -450,6 +450,10 @@ public abstract class ApplicationYamlAssistContext extends AbstractYamlAssistCon
|
||||
ScoreableProposal completion = completionFactory.property(
|
||||
doc.getDocument(), edits, match, typeUtil
|
||||
);
|
||||
String prefix = indexNav.getPrefix();
|
||||
if (StringUtil.hasText(prefix)) {
|
||||
completion = completion.dropLabelPrefix(prefix.length()+1);
|
||||
}
|
||||
if (getContextRoot(doc).exists(YamlPath.fromProperty(match.data.getId()))) {
|
||||
completion.deemphasize(DEEMP_EXISTS);
|
||||
}
|
||||
@@ -632,7 +636,7 @@ public abstract class ApplicationYamlAssistContext extends AbstractYamlAssistCon
|
||||
private static List<IJavaElement> getAllJavaElements(TypeUtil typeUtil, Type parentType, String propName) {
|
||||
if (propName!=null) {
|
||||
Type beanType = parentType;
|
||||
if (TypeUtil.isMap(beanType)) {
|
||||
if (typeUtil.isMap(beanType)) {
|
||||
Type keyType = typeUtil.getKeyType(beanType);
|
||||
if (keyType!=null && typeUtil.isEnum(keyType)) {
|
||||
IField field = typeUtil.getEnumConstant(keyType, propName);
|
||||
|
||||
@@ -224,7 +224,7 @@ public class ApplicationYamlASTReconciler implements YamlASTReconciler {
|
||||
checkForDuplicateKeys(mapping);
|
||||
if (typeUtil.isAtomic(type)) {
|
||||
expectTypeFoundMapping(type, mapping);
|
||||
} else if (TypeUtil.isMap(type) || TypeUtil.isSequencable(type)) {
|
||||
} else if (typeUtil.isMap(type) || typeUtil.isSequencable(type)) {
|
||||
Type keyType = typeUtil.getKeyType(type);
|
||||
Type valueType = TypeUtil.getDomainType(type);
|
||||
if (keyType!=null) {
|
||||
@@ -280,7 +280,7 @@ public class ApplicationYamlASTReconciler implements YamlASTReconciler {
|
||||
private void reconcile(YamlFileAST root, SequenceNode seq, Type type) {
|
||||
if (typeUtil.isAtomic(type)) {
|
||||
expectTypeFoundSequence(type, seq);
|
||||
} else if (TypeUtil.isSequencable(type)) {
|
||||
} else if (typeUtil.isSequencable(type)) {
|
||||
Type domainType = TypeUtil.getDomainType(type);
|
||||
if (domainType!=null) {
|
||||
for (Node element : seq.getValue()) {
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.springframework.ide.vscode.boot.properties.reconcile.ApplicationPropertiesProblemType.PROP_DUPLICATE_KEY;
|
||||
@@ -25,6 +26,7 @@ import java.util.List;
|
||||
|
||||
import org.eclipse.lsp4j.CompletionItem;
|
||||
import org.eclipse.lsp4j.Diagnostic;
|
||||
import org.eclipse.lsp4j.TextEdit;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -85,6 +87,93 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
|
||||
);
|
||||
editor.assertProblems("no-bool|boolean");
|
||||
}
|
||||
|
||||
@Test public void abbreviateLongPrefixCompletions() throws Exception {
|
||||
//See: https://github.com/spring-projects/sts4/issues/361
|
||||
Editor editor;
|
||||
|
||||
data("spring.data.jpa.very.long.foobar", "java.lang.String", null, null);
|
||||
data("spring.data.jpa.very.long.barbar", "java.lang.String", null, null);
|
||||
data("spring.data.jpa.very.long.foofoo", "java.lang.String", null, null);
|
||||
data("spring.data.jpa.very.long.barfoo", "java.lang.String", null, null);
|
||||
data("spring.data.jpa.very.long.foobar.more", "java.lang.String", null, null);
|
||||
data("spring.data.jpa.very.long.barbar.more", "java.lang.String", null, null);
|
||||
data("spring.data.jpa.very.long.foofoo.more", "java.lang.String", null, null);
|
||||
data("spring.data.jpa.very.long.barfoo.more", "java.lang.String", null, null);
|
||||
|
||||
|
||||
editor = newEditor(
|
||||
"spring.data.jpa.very.bar<*>"
|
||||
);
|
||||
editor.assertCompletions(
|
||||
"spring.data.jpa.very.long.barbar=<*>",
|
||||
"spring.data.jpa.very.long.barfoo=<*>",
|
||||
"spring.data.jpa.very.long.foobar=<*>",
|
||||
"spring.data.jpa.very.long.barbar.more=<*>",
|
||||
"spring.data.jpa.very.long.barfoo.more=<*>",
|
||||
"spring.data.jpa.very.long.foobar.more=<*>"
|
||||
);
|
||||
|
||||
List<CompletionItem> completions = editor.assertCompletionLabels(
|
||||
"long.barbar",
|
||||
"long.barfoo",
|
||||
"long.foobar",
|
||||
"long.barbar.more",
|
||||
"long.barfoo.more",
|
||||
"long.foobar.more"
|
||||
);
|
||||
for (CompletionItem c : completions) {
|
||||
TextEdit edit = c.getTextEdit();
|
||||
assertEquals("bar", editor.getText(edit.getRange()));
|
||||
}
|
||||
|
||||
editor = newEditor(
|
||||
"spring.data.jpa.vr<*>"
|
||||
);
|
||||
completions = editor.assertCompletionLabels(
|
||||
"very.long.barbar",
|
||||
"very.long.barfoo",
|
||||
"very.long.foobar",
|
||||
"very.long.foofoo",
|
||||
"very.long.barbar.more",
|
||||
"very.long.barfoo.more",
|
||||
"very.long.foobar.more",
|
||||
"very.long.foofoo.more"
|
||||
);
|
||||
for (CompletionItem c : completions) {
|
||||
TextEdit edit = c.getTextEdit();
|
||||
assertEquals("vr", editor.getText(edit.getRange()));
|
||||
}
|
||||
|
||||
editor = newEditor(
|
||||
"spring.data.jpa.very.<*>"
|
||||
);
|
||||
editor.assertCompletions(
|
||||
"spring.data.jpa.very.long.barbar=<*>",
|
||||
"spring.data.jpa.very.long.barbar.more=<*>",
|
||||
"spring.data.jpa.very.long.barfoo=<*>",
|
||||
"spring.data.jpa.very.long.barfoo.more=<*>",
|
||||
"spring.data.jpa.very.long.foobar=<*>",
|
||||
"spring.data.jpa.very.long.foobar.more=<*>",
|
||||
"spring.data.jpa.very.long.foofoo=<*>",
|
||||
"spring.data.jpa.very.long.foofoo.more=<*>"
|
||||
);
|
||||
completions = editor.assertCompletionLabels(
|
||||
"long.barbar",
|
||||
"long.barbar.more",
|
||||
"long.barfoo",
|
||||
"long.barfoo.more",
|
||||
"long.foobar",
|
||||
"long.foobar.more",
|
||||
"long.foofoo",
|
||||
"long.foofoo.more"
|
||||
);
|
||||
for (CompletionItem c : completions) {
|
||||
TextEdit edit = c.getTextEdit();
|
||||
assertEquals("", editor.getText(edit.getRange()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReconcileCatchesParseError() throws Exception {
|
||||
|
||||
@@ -71,6 +71,98 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Test public void abbreviateLongPrefixCompletions() throws Exception {
|
||||
//See: https://github.com/spring-projects/sts4/issues/361
|
||||
Editor editor;
|
||||
|
||||
data("spring.data.jpa.very.long.foobar", "java.lang.String", null, null);
|
||||
data("spring.data.jpa.very.long.barbar", "java.lang.String", null, null);
|
||||
data("spring.data.jpa.very.long.foofoo", "java.lang.String", null, null);
|
||||
data("spring.data.jpa.very.long.barfoo", "java.lang.String", null, null);
|
||||
data("spring.data.jpa.very.long.foobar.more", "java.lang.String", null, null);
|
||||
data("spring.data.jpa.very.long.barbar.more", "java.lang.String", null, null);
|
||||
data("spring.data.jpa.very.long.foofoo.more", "java.lang.String", null, null);
|
||||
data("spring.data.jpa.very.long.barfoo.more", "java.lang.String", null, null);
|
||||
|
||||
|
||||
editor = newEditor(
|
||||
"spring:\n" +
|
||||
" data:\n" +
|
||||
" jpa:\n" +
|
||||
" very:\n" +
|
||||
" bar<*>"
|
||||
);
|
||||
editor.assertCompletions(
|
||||
"spring:\n" +
|
||||
" data:\n" +
|
||||
" jpa:\n" +
|
||||
" very:\n" +
|
||||
" long:\n" +
|
||||
" barbar: <*>",
|
||||
"spring:\n" +
|
||||
" data:\n" +
|
||||
" jpa:\n" +
|
||||
" very:\n" +
|
||||
" long:\n" +
|
||||
" barfoo: <*>",
|
||||
"spring:\n" +
|
||||
" data:\n" +
|
||||
" jpa:\n" +
|
||||
" very:\n" +
|
||||
" long:\n" +
|
||||
" foobar: <*>",
|
||||
"spring:\n" +
|
||||
" data:\n" +
|
||||
" jpa:\n" +
|
||||
" very:\n" +
|
||||
" long:\n" +
|
||||
" barbar:\n"+
|
||||
" more: <*>",
|
||||
"spring:\n" +
|
||||
" data:\n" +
|
||||
" jpa:\n" +
|
||||
" very:\n" +
|
||||
" long:\n" +
|
||||
" barfoo:\n"+
|
||||
" more: <*>",
|
||||
"spring:\n" +
|
||||
" data:\n" +
|
||||
" jpa:\n" +
|
||||
" very:\n" +
|
||||
" long:\n" +
|
||||
" foobar:\n"+
|
||||
" more: <*>"
|
||||
);
|
||||
|
||||
editor.assertCompletionLabels(
|
||||
"long.barbar",
|
||||
"long.barfoo",
|
||||
"long.foobar",
|
||||
"long.barbar.more",
|
||||
"long.barfoo.more",
|
||||
"long.foobar.more"
|
||||
);
|
||||
|
||||
editor = newEditor(
|
||||
"spring:\n" +
|
||||
" data:\n" +
|
||||
" jpa:\n" +
|
||||
" vr<*>"
|
||||
);
|
||||
editor.assertCompletionLabels(
|
||||
"very.long.barbar",
|
||||
"very.long.barfoo",
|
||||
"very.long.foobar",
|
||||
"very.long.foofoo",
|
||||
"very.long.barbar.more",
|
||||
"very.long.barfoo.more",
|
||||
"very.long.foobar.more",
|
||||
"very.long.foofoo.more"
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test public void bug_GH_327() throws Exception {
|
||||
//See https://github.com/spring-projects/sts4/issues/327
|
||||
data("spring.resources.static-locations", "java.lang.Boolean", null, "Blah");
|
||||
@@ -3358,7 +3450,7 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest {
|
||||
" p<*>"
|
||||
);
|
||||
|
||||
editor.assertCompletionLabels("server.port");
|
||||
editor.assertCompletionLabels("port");
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user