/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.codeInsight.lookup.impl;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementPresentation;
import com.intellij.openapi.editor.*;
import com.intellij.openapi.editor.colors.EditorFontType;
import com.intellij.openapi.editor.impl.EditorImpl;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.refactoring.rename.inplace.InplaceRefactoring;
import com.intellij.ui.JBColor;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.FList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
/**
* @author peter
*/
class LookupPreview {
private final List<Inlay> myInlays = new ArrayList<>();
private final LookupImpl myLookup;
LookupPreview(LookupImpl lookup) {
myLookup = lookup;
}
void updatePreview(@Nullable LookupElement item) {
if (!Registry.is("ide.lookup.preview.insertion")) return;
myInlays.forEach(Disposer::dispose);
myInlays.clear();
String suffix = getSuffixText(item);
Editor editor = myLookup.getTopLevelEditor();
if (!suffix.isEmpty() && editor instanceof EditorImpl &&
!editor.getSelectionModel().hasSelection() &&
InplaceRefactoring.getActiveInplaceRenamer(editor) == null) {
myLookup.performGuardedChange(() -> {
for (Caret caret : editor.getCaretModel().getAllCarets()) {
ensureCaretBeforeInlays(caret);
addInlay(suffix, caret.getOffset());
}
});
}
}
private static void ensureCaretBeforeInlays(Caret caret) {
LogicalPosition position = caret.getLogicalPosition();
if (position.leansForward) {
caret.moveToLogicalPosition(position.leanForward(false));
}
}
private String getSuffixText(@Nullable LookupElement item) {
if (item != null) {
String itemText = StringUtil.notNullize(LookupElementPresentation.renderElement(item).getItemText());
String prefix = myLookup.itemPattern(item);
if (prefix.isEmpty()) {
return itemText;
}
FList<TextRange> fragments = LookupCellRenderer.getMatchingFragments(prefix, itemText);
if (fragments != null && !fragments.isEmpty()) {
List<TextRange> list = ContainerUtil.newArrayList(fragments);
return itemText.substring(list.get(list.size() - 1).getEndOffset(), itemText.length());
}
}
return "";
}
private void addInlay(String suffix, int caretOffset) {
Inlay inlay = myLookup.getTopLevelEditor().getInlayModel().addInlineElement(caretOffset, createGrayRenderer(suffix));
if (inlay != null) {
myInlays.add(inlay);
Disposer.register(myLookup, inlay);
}
}
@NotNull
private static EditorCustomElementRenderer createGrayRenderer(final String suffix) {
return new EditorCustomElementRenderer() {
@Override
public int calcWidthInPixels(@NotNull Editor editor) {
return editor.getContentComponent().getFontMetrics(getFont(editor)).stringWidth(suffix);
}
@Override
public void paint(@NotNull Editor editor, @NotNull Graphics g, @NotNull Rectangle r) {
g.setColor(JBColor.GRAY);
g.setFont(getFont(editor));
g.drawString(suffix, r.x, r.y + ((EditorImpl)editor).getAscent());
}
private Font getFont(@NotNull Editor editor) {
return editor.getColorsScheme().getFont(EditorFontType.PLAIN);
}
};
}
}