Merge branch 'denofevil/rd-param-info'

This commit is contained in:
Dennis Ushakov
2018-05-10 00:21:53 +03:00
5 changed files with 130 additions and 20 deletions
@@ -13,6 +13,7 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.keymap.KeymapUtil;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.ui.*;
import com.intellij.util.Function;
@@ -28,6 +29,7 @@ import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
import java.util.*;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -86,7 +88,7 @@ public class ParameterInfoComponent extends JPanel {
super(new BorderLayout());
myRequestFocus = requestFocus;
if (!ApplicationManager.getApplication().isUnitTestMode()) {
if (!ApplicationManager.getApplication().isUnitTestMode() && !ApplicationManager.getApplication().isHeadlessEnvironment()) {
JComponent editorComponent = editor.getComponent();
JLayeredPane layeredPane = editorComponent.getRootPane().getLayeredPane();
myWidthLimit = layeredPane.getWidth();
@@ -169,6 +171,7 @@ public class ParameterInfoComponent extends JPanel {
private final boolean mySingleParameterInfo;
private int i;
private Function<String, String> myEscapeFunction;
private final ParameterInfoController.Model result = new ParameterInfoController.Model();
public MyParameterContext(boolean singleParameterInfo) {
mySingleParameterInfo = singleParameterInfo;
@@ -182,6 +185,29 @@ public class ParameterInfoComponent extends JPanel {
boolean strikeout,
boolean isDisabledBeforeHighlight,
Color background) {
List<String> split = StringUtil.split(text, ",", false);
StringBuilder plainLine = new StringBuilder();
final List<Integer> startOffsets = new ArrayList<>();
final List<Integer> endOffsets = new ArrayList<>();
TextRange highlightRange = highlightStartOffset >=0 && highlightEndOffset >= highlightStartOffset ?
new TextRange(highlightStartOffset, highlightEndOffset) :
null;
for (int j = 0; j < split.size(); j++) {
String line = split.get(j);
int startOffset = plainLine.length();
startOffsets.add(startOffset);
plainLine.append(line);
int endOffset = plainLine.length();
endOffsets.add(endOffset);
if (highlightRange != null && highlightRange.intersects(new TextRange(startOffset, endOffset))) {
result.current = j;
}
}
ParameterInfoController.SignatureItem item = new ParameterInfoController.SignatureItem(plainLine.toString(), strikeout, isDisabled,
startOffsets, endOffsets);
result.signatures.add(item);
final String resultedText =
myPanels[i].setup(text, myEscapeFunction, highlightStartOffset, highlightEndOffset, isDisabled, strikeout, isDisabledBeforeHighlight, background);
myPanels[i].setBorder(isLastParameterOwner() || isSingleParameterInfo() ? EMPTY_BORDER : BOTTOM_BORDER);
@@ -196,7 +222,7 @@ public class ParameterInfoComponent extends JPanel {
@Override
public String setupUIComponentPresentation(final String[] texts, final EnumSet<Flag>[] flags, final Color background) {
final String resultedText = myPanels[i].setup(texts, myEscapeFunction, flags, background);
final String resultedText = myPanels[i].setup(result, texts, myEscapeFunction, flags, background);
myPanels[i].setBorder(isLastParameterOwner() || isSingleParameterInfo() ? EMPTY_BORDER : BOTTOM_BORDER);
return resultedText;
}
@@ -252,7 +278,7 @@ public class ParameterInfoComponent extends JPanel {
}
}
public void update(boolean singleParameterInfo) {
public ParameterInfoController.Model update(boolean singleParameterInfo) {
MyParameterContext context = new MyParameterContext(singleParameterInfo);
for (int i = 0; i < myObjects.length; i++) {
@@ -270,6 +296,7 @@ public class ParameterInfoComponent extends JPanel {
}
if (myShortcutLabel != null) myShortcutLabel.setVisible(!singleParameterInfo);
return context.result;
}
public Object[] getObjects() {
@@ -388,7 +415,8 @@ public class ParameterInfoComponent extends JPanel {
return escapeFunction == null ? line : escapeFunction.fun(line);
}
public String setup(final String[] texts,
public String setup(final ParameterInfoController.Model result,
final String[] texts,
Function<String, String> escapeFunction,
final EnumSet<ParameterInfoUIContextEx.Flag>[] flags,
final Color background) {
@@ -398,16 +426,24 @@ public class ParameterInfoComponent extends JPanel {
int index = 0;
int curOffset = 0;
final ArrayList<OneLineComponent> components = new ArrayList<>();
final List<Integer> startOffsets = new ArrayList<>();
final List<Integer> endOffsets = new ArrayList<>();
Map<TextRange, ParameterInfoUIContextEx.Flag> flagsMap = new TreeMap<>(TEXT_RANGE_COMPARATOR);
String line = "";
StringBuilder fullLine = new StringBuilder();
StringBuilder line = new StringBuilder();
for (int i = 0; i < texts.length; i++) {
String paramText = escapeString(texts[i], escapeFunction);
if (paramText == null) break;
line += texts[i];
startOffsets.add(fullLine.length());
fullLine.append(texts[i]);
endOffsets.add(fullLine.length());
line.append(texts[i]);
final EnumSet<ParameterInfoUIContextEx.Flag> flag = flags[i];
if (flag.contains(ParameterInfoUIContextEx.Flag.HIGHLIGHT)) {
result.current = i;
flagsMap.put(TextRange.create(curOffset, curOffset + paramText.trim().length()), ParameterInfoUIContextEx.Flag.HIGHLIGHT);
}
@@ -422,18 +458,21 @@ public class ParameterInfoComponent extends JPanel {
curOffset += paramText.length();
if (line.length() >= 50) {
final OneLineComponent component = new OneLineComponent();
buf.append(component.setup(escapeString(line, escapeFunction), flagsMap, background));
buf.append(component.setup(escapeString(line.toString(), escapeFunction), flagsMap, background));
add(component, new GridBagConstraints(0, index, 1, 1, 1, 0, GridBagConstraints.WEST,
GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
index += 1;
flagsMap.clear();
curOffset = 0;
line = "";
line = new StringBuilder();
components.add(component);
}
}
ParameterInfoController.SignatureItem item = new ParameterInfoController.SignatureItem(fullLine.toString(), false, false,
startOffsets, endOffsets);
result.signatures.add(item);
final OneLineComponent component = new OneLineComponent();
buf.append(component.setup(escapeString(line, escapeFunction), flagsMap, background));
buf.append(component.setup(escapeString(line.toString(), escapeFunction), flagsMap, background));
add(component, new GridBagConstraints(0, index, 1, 1, 1, 0, GridBagConstraints.WEST,
GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
components.add(component);
@@ -67,6 +67,7 @@ public class ParameterInfoController extends UserDataHolderBase implements Visib
private final CaretListener myEditorCaretListener;
@NotNull private final ParameterInfoHandler<Object, Object> myHandler;
private final MyBestLocationPointProvider myProvider;
private final ParameterInfoListener[] myListeners;
private final Alarm myAlarm = new Alarm();
private static final int DELAY = 200;
@@ -129,6 +130,7 @@ public class ParameterInfoController extends UserDataHolderBase implements Visib
myEditor = editor;
myHandler = handler;
myProvider = new MyBestLocationPointProvider(editor);
myListeners = ParameterInfoListener.EP_NAME.getExtensions();
myLbraceMarker = editor.getDocument().createRangeMarker(lbraceOffset, lbraceOffset);
myComponent = new ParameterInfoComponent(descriptors, editor, handler, requestFocus, true);
myHint = createHint();
@@ -197,7 +199,7 @@ public class ParameterInfoController extends UserDataHolderBase implements Visib
public void dispose(){
if (myDisposed) return;
myDisposed = true;
myHint.hide();
hideHint();
myHandler.dispose(new MyDeleteParameterInfoContext());
List<ParameterInfoController> allControllers = getAllControllers(myEditor);
allControllers.remove(this);
@@ -213,7 +215,7 @@ public class ParameterInfoController extends UserDataHolderBase implements Visib
public void showHint(boolean requestFocus, boolean singleParameterInfo) {
if (myHint.isVisible()) {
myHint.getComponent().remove(myComponent);
myHint.hide();
hideHint();
myHint = createHint();
}
@@ -291,7 +293,7 @@ public class ParameterInfoController extends UserDataHolderBase implements Visib
}
public void updateComponent(){
if (!myKeepOnHintHidden && !myHint.isVisible() || myEditor instanceof EditorWindow && !((EditorWindow)myEditor).isValid()) {
if (!myKeepOnHintHidden && !myHint.isVisible() && !ApplicationManager.getApplication().isHeadlessEnvironment() || myEditor instanceof EditorWindow && !((EditorWindow)myEditor).isValid()) {
Disposer.dispose(this);
return;
}
@@ -310,14 +312,22 @@ public class ParameterInfoController extends UserDataHolderBase implements Visib
boolean knownParameter = (myComponent.getObjects().length == 1 || myComponent.getHighlighted() != null) &&
myComponent.getCurrentParameterIndex() != -1;
if (mySingleParameterInfo && !knownParameter && myHint.isVisible()) {
myHint.hide();
hideHint();
}
if (myKeepOnHintHidden && knownParameter && !myHint.isVisible()) {
AutoPopupController.getInstance(myProject).autoPopupParameterInfo(myEditor, null);
}
if (!myDisposed && myHint.isVisible() && !myEditor.isDisposed() &&
(myEditor.getComponent().getRootPane() != null || ApplicationManager.getApplication().isUnitTestMode())) {
myComponent.update(mySingleParameterInfo);
if (!myDisposed && (myHint.isVisible() && !myEditor.isDisposed() &&
(myEditor.getComponent().getRootPane() != null || ApplicationManager.getApplication().isUnitTestMode()) ||
ApplicationManager.getApplication().isHeadlessEnvironment())) {
Model result = myComponent.update(mySingleParameterInfo);
result.project = myProject;
result.range = myComponent.getParameterOwner().getTextRange();
result.editor = myEditor;
for (ParameterInfoListener listener : myListeners) {
listener.hintUpdated(result);
}
if (ApplicationManager.getApplication().isHeadlessEnvironment()) return;
IdeTooltip tooltip = myHint.getCurrentIdeTooltip();
short position = tooltip != null
? toShort(tooltip.getPreferredPosition())
@@ -329,7 +339,7 @@ public class ParameterInfoController extends UserDataHolderBase implements Visib
}
}
else {
myHint.hide();
hideHint();
if (!myKeepOnHintHidden) {
Disposer.dispose(this);
}
@@ -499,7 +509,8 @@ public class ParameterInfoController extends UserDataHolderBase implements Visib
VisualPosition pos,
LightweightHint hint,
short preferredPosition, boolean showLookupHint) {
if (ApplicationManager.getApplication().isUnitTestMode()) return Pair.pair(new Point(), HintManager.DEFAULT);
if (ApplicationManager.getApplication().isUnitTestMode() ||
ApplicationManager.getApplication().isHeadlessEnvironment()) return Pair.pair(new Point(), HintManager.DEFAULT);
HintManagerImpl hintManager = HintManagerImpl.getInstanceImpl();
Dimension hintSize = hint.getComponent().getPreferredSize();
@@ -580,7 +591,7 @@ public class ParameterInfoController extends UserDataHolderBase implements Visib
@Override
public void removeHint() {
myHint.hide();
hideHint();
if (!myKeepOnHintHidden) Disposer.dispose(ParameterInfoController.this);
}
@@ -659,6 +670,41 @@ public class ParameterInfoController extends UserDataHolderBase implements Visib
}
}
protected void hideHint() {
myHint.hide();
for (ParameterInfoListener listener : myListeners) {
listener.hintHidden(myProject);
}
}
public static class SignatureItem {
public final String text;
public final boolean deprecated;
public final boolean disabled;
public final List<Integer> startOffsets;
public final List<Integer> endOffsets;
public SignatureItem(String text,
boolean deprecated,
boolean disabled,
List<Integer> startOffsets,
List<Integer> endOffsets) {
this.text = text;
this.deprecated = deprecated;
this.disabled = disabled;
this.startOffsets = startOffsets;
this.endOffsets = endOffsets;
}
}
public static class Model {
public final List<SignatureItem> signatures = new ArrayList<>();
public int current = -1;
public TextRange range;
public Editor editor;
public Project project;
}
private static class MyBestLocationPointProvider {
private final Editor myEditor;
private int previousOffset = -1;
@@ -0,0 +1,22 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.codeInsight.hint;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.project.Project;
public interface ParameterInfoListener {
ExtensionPointName<ParameterInfoListener> EP_NAME = new ExtensionPointName<>("com.intellij.codeInsight.parameterInfo.listener");
/**
* This method is invoked when parameter info hint content is updated (including first time show) and there are some signatures to show
* @param result model describing signatures shown and current context
*/
void hintUpdated(ParameterInfoController.Model result);
/**
* This method is invoked when parameter info hint is hidden due to closing the hint, leaving parameters range area or because there are
* no signatures to show
* @param project for which hint was shown originally
*/
void hintHidden(Project project);
}
@@ -118,7 +118,9 @@ public class ShowParameterInfoContext implements CreateParameterInfoContext {
PsiDocumentManager.getInstance(project).performLaterWhenAllCommitted(() -> {
if (editor.isDisposed() || DumbService.isDumb(project) ||
(!ApplicationManager.getApplication().isUnitTestMode() && !editor.getComponent().isShowing())) return;
(!ApplicationManager.getApplication().isUnitTestMode() &&
!ApplicationManager.getApplication().isHeadlessEnvironment() &&
!editor.getComponent().isShowing())) return;
final Document document = editor.getDocument();
if (document.getTextLength() < elementStart) return;
@@ -620,6 +620,7 @@
<extensionPoint name="codeInsight.parameterInfo" beanClass="com.intellij.lang.LanguageExtensionPoint">
<with attribute="implementationClass" implements="com.intellij.lang.parameterInfo.ParameterInfoHandler"/>
</extensionPoint>
<extensionPoint name="codeInsight.parameterInfo.listener" interface="com.intellij.codeInsight.hint.ParameterInfoListener" />
<extensionPoint name="codeInsight.parameterNameHints" beanClass="com.intellij.lang.LanguageExtensionPoint">
<with attribute="implementationClass" implements="com.intellij.codeInsight.hints.InlayParameterHintsProvider"/>
</extensionPoint>