emmet + live templates in tooltip preview: insert variables

- insert default variable value or variable name, so that preview text make sense (and be highlighted correctly)
- test for the case emmet + vue

related to WEB-29541
This commit is contained in:
Irina.Chernushina
2017-11-06 09:13:59 +01:00
parent fba1cddfd8
commit 1e970cc023
3 changed files with 50 additions and 7 deletions
@@ -19,13 +19,17 @@ import com.intellij.codeInsight.template.impl.TemplateImpl;
import com.intellij.codeInsight.template.impl.Variable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.containers.HashMap;
import com.intellij.util.containers.HashSet;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* @author Eugene.Kudelevsky
@@ -63,6 +67,23 @@ public class LiveTemplateBuilder {
return myText;
}
@NotNull
public String getTextForPreview() {
if (myVariables.isEmpty()) return myText.toString();
final StringBuilder sb = new StringBuilder(myText);
final Ref<Integer> offset = new Ref<>(0);
final Map<String, Variable> map = myVariables.stream().collect(Collectors.toMap(Variable::getName, Function.identity()));
myVariableOccurrences.forEach(vo -> {
final Variable variable = map.get(vo.myName);
if (variable == null) return;
String varReplacement = StringUtil.unquoteString(variable.getDefaultValueString());
varReplacement = StringUtil.isEmptyOrSpaces(varReplacement) ? vo.myName : varReplacement;
sb.replace(vo.myOffset + offset.get(), vo.myOffset + offset.get(), varReplacement);
offset.set(offset.get() + varReplacement.length());
});
return sb.toString();
}
public static boolean isEndVariable(@NotNull String name) {
return name.startsWith(END_PREFIX);
}
@@ -39,6 +39,7 @@ import com.intellij.ui.LightweightHint;
import com.intellij.ui.components.JBPanel;
import com.intellij.util.Alarm;
import com.intellij.util.DocumentUtil;
import com.intellij.util.ObjectUtils;
import com.intellij.util.Producer;
import com.intellij.util.ui.JBUI;
import org.jetbrains.annotations.NotNull;
@@ -53,13 +54,16 @@ public class EmmetPreviewHint extends LightweightHint implements Disposable {
@NotNull private final Editor myParentEditor;
@NotNull private final Editor myEditor;
@NotNull private final Alarm myAlarm = new Alarm(this);
private boolean isDisposed = false;
private volatile boolean isDisposed = false;
private EmmetPreviewHint(@NotNull JBPanel panel, @NotNull Editor editor, @NotNull Editor parentEditor) {
super(panel);
myParentEditor = parentEditor;
myEditor = editor;
final Disposable parentDisposable = ObjectUtils.coalesce(ObjectUtils.tryCast(parentEditor, Disposable.class), parentEditor.getProject());
Disposer.register(parentDisposable, this);
final Editor topLevelEditor = InjectedLanguageUtil.getTopLevelEditor(myParentEditor);
EditorFactory.getInstance().addEditorFactoryListener(new EditorFactoryAdapter() {
@Override
@@ -199,6 +203,7 @@ public class EmmetPreviewHint extends LightweightHint implements Disposable {
public void dispose() {
isDisposed = true;
myAlarm.cancelAllRequests();
super.hide();
EmmetPreviewHint existingBalloon = myParentEditor.getUserData(KEY);
if (existingBalloon == this) {
myParentEditor.putUserData(KEY, null);
@@ -15,6 +15,7 @@
*/
package com.intellij.codeInsight.template.emmet;
import com.intellij.codeInsight.template.LiveTemplateBuilder;
import com.intellij.codeInsight.template.emmet.generators.XmlZenCodingGenerator;
import com.intellij.codeInsight.template.emmet.generators.ZenCodingGenerator;
import com.intellij.codeInsight.template.impl.TemplateImpl;
@@ -26,6 +27,7 @@ import com.intellij.openapi.editor.event.CaretEvent;
import com.intellij.openapi.editor.event.CaretListener;
import com.intellij.openapi.editor.event.DocumentEvent;
import com.intellij.openapi.editor.event.DocumentListener;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDocumentManager;
@@ -51,12 +53,11 @@ public class EmmetPreviewUtil {
final String templatePrefix = new ZenCodingTemplate().computeTemplateKeyWithoutContextChecking(callback);
if (templatePrefix != null) {
try {
ZenCodingTemplate.expand(templatePrefix, callback, generator, Collections.emptyList(),
expandPrimitiveAbbreviations, 0);
TemplateImpl template = callback.getGeneratedTemplate();
String templateText = template != null ? template.getTemplateText() : null;
if (!StringUtil.isEmpty(templateText)) {
return template.isToReformat() ? reformatTemplateText(file, templateText) : templateText;
final int limit = Registry.intValue("emmet.segments.limit");
ZenCodingTemplate.expand(templatePrefix, callback, generator, Collections.emptyList(), expandPrimitiveAbbreviations, limit);
final TemplateImpl template = callback.getGeneratedTemplate();
if (template != null) {
return getFormattedText(template, file, limit);
}
}
catch (EmmetException e) {
@@ -68,6 +69,22 @@ public class EmmetPreviewUtil {
return null;
}
@Nullable
private static String getFormattedText(@NotNull final TemplateImpl template, @NotNull final PsiFile file, int limit) {
final String templateText;
if (template.getVariableCount() > 0 && template.getVariableCount() < limit/2) {
final LiveTemplateBuilder builder = new LiveTemplateBuilder(false, limit);
builder.insertTemplate(0, template, Collections.emptyMap());
templateText = builder.getTextForPreview();
} else {
templateText = template.getTemplateText();
}
if (!StringUtil.isEmpty(templateText)) {
return template.isToReformat() ? reformatTemplateText(file, templateText) : templateText;
}
return null;
}
public static void addEmmetPreviewListeners(@NotNull final Editor editor,
@NotNull final PsiFile file,
final boolean expandPrimitiveAbbreviations) {