in cell/src/main/java/jetbrains/jetpad/cell/completion/CompletionSupport.java [209:355]
public static TextCell showSideTransformPopup(
final Cell cell,
final Property<Cell> targetPopup,
final CompletionSupplier supplier,
final boolean endRT) {
final CellContainer container = cell.getContainer();
final Value<Boolean> completed = new Value<>(false);
final Value<Boolean> dismissed = new Value<>(false);
final Runnable restoreState = container.saveState();
final Function<CompletionItem, CompletionItem> wrap = new Function<CompletionItem, CompletionItem>() {
@Override
public CompletionItem apply(CompletionItem input) {
return new WrapperCompletionItem(input) {
@Override
public Runnable complete(String text) {
completed.set(true);
return super.complete(text);
}
};
}
};
final HorizontalCell popup = new HorizontalCell();
final TextCell textCell = new TextCell();
final Value<Handler<Boolean>> dismiss = new Value<>();
textCell.focusable().set(true);
final Registration traitReg = textCell.addTrait(new TextEditingTrait() {
@Override
public Object get(Cell cell, CellTraitPropertySpec<?> spec) {
if (spec == Completion.COMPLETION) {
return new CompletionSupplier() {
@Override
public Iterable<CompletionItem> get(CompletionParameters cp) {
return FluentIterable.from(supplier.get(wrap(cp))).transform(wrap);
}
@Override
public Async<Iterable<CompletionItem>> getAsync(CompletionParameters cp) {
return Asyncs.map(supplier.getAsync(wrap(cp)), new Function<Iterable<CompletionItem>, Iterable<CompletionItem>>() {
@Override
public Iterable<CompletionItem> apply(Iterable<CompletionItem> input) {
return FluentIterable.from(input).transform(wrap);
}
});
}
};
}
return super.get(cell, spec);
}
@Override
public void onPropertyChanged(Cell cell, CellPropertySpec<?> prop, PropertyChangeEvent<?> e) {
if (prop == TextCell.TEXT) {
PropertyChangeEvent<String> event = (PropertyChangeEvent<String>) e;
if (Strings.isNullOrEmpty(event.getNewValue())) {
dismiss.get().handle(false);
}
}
super.onPropertyChanged(cell, prop, e);
}
@Override
public void onKeyPressed(Cell cell, KeyEvent event) {
if (event.is(Key.ESCAPE)) {
dismiss.get().handle(false);
event.consume();
return;
}
super.onKeyPressed(cell, event);
}
@Override
protected boolean onAfterType(TextCell editor) {
if (super.onAfterType(editor)) return true;
if (!editor.isEnd()) return false;
String text = editor.text().get();
final CompletionItems completion = new CompletionItems(supplier.get(wrap(CompletionParameters.EMPTY)));
if (completion.hasSingleMatch(text, cell.get(TextEditing.EAGER_COMPLETION))) {
completion.matches(text).get(0).complete(text).run();
return true;
}
String prefix = text.substring(0, text.length() - 1);
String suffix = text.substring(text.length() - 1);
if (completion.matches(prefix).size() == 1 && completion.prefixedBy(text).isEmpty()) {
completion.matches(prefix).get(0).complete(prefix).run();
for (int i = 0; i < suffix.length(); i++) {
container.keyTyped(new KeyEvent(Key.UNKNOWN, suffix.charAt(i), Collections.<ModifierKey>emptySet()));
}
}
return true;
}
@Override
public void onFocusLost(Cell cell, FocusEvent event) {
super.onFocusLost(cell, event);
dismiss.get().handle(true);
}
private CompletionParameters wrap(final CompletionParameters otherParams) {
return new BaseCompletionParameters() {
@Override
public boolean isEndRightTransform() {
return endRT;
}
@Override
public boolean isMenu() {
return otherParams.isMenu();
}
};
}
});
popup.children().add(textCell);
if (targetPopup.get() != null) {
throw new IllegalStateException();
}
targetPopup.set(popup);
textCell.focus();
dismiss.set(new Handler<Boolean>() {
@Override
public void handle(Boolean focusLoss) {
if (dismissed.get()) return;
dismissed.set(true);
popup.removeFromParent();
traitReg.remove();
if (!completed.get() && !focusLoss) {
restoreState.run();
}
}
});
return textCell;
}