public static TextCell showSideTransformPopup()

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;
  }