private CellTrait createTargetTrait()

in hybrid/src/main/java/jetbrains/jetpad/hybrid/BaseHybridSynchronizer.java [190:371]


  private CellTrait createTargetTrait() {
    return new CellTrait() {
      @Override
      public Object get(Cell cell, CellTraitPropertySpec<?> spec) {
        if (spec == HYBRID_SYNCHRONIZER) {
          return BaseHybridSynchronizer.this;
        }
        if (spec == CellStateHandler.PROPERTY) {
          return getCellStateHandler();
        }

        return super.get(cell, spec);
      }

      @Override
      public void onKeyPressed(Cell cell, KeyEvent event) {
        Cell focusedCell = cell.getContainer().focusedCell.get();
        if (myTargetList.contains(focusedCell)) {
          Cell currentCell = cell.getContainer().focusedCell.get();
          if (!hasSelection()) {
            if (event.is(KeyStrokeSpecs.SELECT_UP) && currentCell != null) {
              mySelectionSupport.select(currentCell, currentCell);
              event.consume();
            }
          } else {
            Range<Integer> currentRange = selection();
            if (event.is(KeyStrokeSpecs.SELECT_UP)) {
              ParseNode parseNode = myTokenListEditor.getParseNode();
              if (parseNode != null) {
                if (!currentRange.equals(parseNode.getRange())) {
                  ParseNode node = ParseNodes.findForRange(parseNode, currentRange);
                  ParseNode parentNode = ParseNodes.nonSameRangeParent(node);
                  if (parentNode != null) {
                    select(parentNode.getRange());
                    event.consume();
                  }
                }
              } else {
                if (!currentRange.equals(Range.closed(0, tokens().size()))) {
                  select(Range.closed(0, tokens().size()));
                  event.consume();
                }
              }
            }

            if (event.is(KeyStrokeSpecs.SELECT_DOWN)) {
              ParseNode parseNode = myTokenListEditor.getParseNode();
              if (parseNode != null) {
                ParseNode node = ParseNodes.findForRange(parseNode, currentRange);
                ParseNode childNode = ParseNodes.nonSameRangeChild(node, myTargetList.indexOf(mySelectionSupport.currentCell()));
                if (childNode != null) {
                  select(childNode.getRange());
                  event.consume();
                  return;
                }
              }

              if (!mySelectionSupport.isCurrentCompletelySelected()) {
                mySelectionSupport.clearSelection();
                event.consume();
              }
            }
          }
        }
        super.onKeyPressed(cell, event);
      }

      @Override
      public void onCopy(Cell cell, CopyCutEvent event) {
        if (canCopy()) {
          event.consume(copy());
          return;
        }
        super.onCopy(cell, event);
      }

      @Override
      public void onCut(Cell cell, CopyCutEvent event) {
        if (canCut()) {
          ClipboardContent content = cut();
          myTokensEditPostProcessor.afterTokensEdit(tokens(), property().get());
          event.consume(content);
          return;
        }
        super.onCut(cell, event);
      }

      @Override
      public void onPaste(Cell cell, PasteEvent event) {
        if (canPaste(event.getContent())) {
          paste(event.getContent());
          myTokensEditPostProcessor.afterTokensEdit(tokens(), property().get());
          event.consume();
          return;
        }
        super.onPaste(cell, event);
      }

      private boolean canPaste(ClipboardContent content) {
        return content.isSupported(TOKENS_CONTENT);
      }

      private void paste(ClipboardContent content) {
        List<Token> tokens = content.get(TOKENS_CONTENT);
        Cell currentCell = mySelectionSupport.currentCell();

        int targetIndex;
        if (currentCell != null) {
          int currentCellIndex = myTargetList.indexOf(currentCell);
          boolean home = Positions.isHomePosition(currentCell);
          boolean end = Positions.isEndPosition(currentCell);
          if (home && end) {
            // One-char token which allows editing at only one side
            if (currentCell instanceof TextTokenCell && ((TextTokenCell) currentCell).noSpaceToLeft()) {
              targetIndex = currentCellIndex + 1;
            } else {
              targetIndex = currentCellIndex;
            }
          } else if (home) {
            targetIndex = currentCellIndex;
          } else {
            targetIndex = currentCellIndex + 1;
          }
        } else {
          targetIndex = 0;
        }

        myTokenListEditor.tokens.addAll(targetIndex, tokens);
        myTokenListEditor.updateToPrintedTokens();
        tokenOperations().select(targetIndex + tokens.size() - 1, LAST).run();
      }

      private boolean canCopy() {
        return hasSelection();
      }

      private ClipboardContent copy() {
        final Range<Integer> selection = selection();
        final List<Token> copiedTokens = new ArrayList<>(selection.upperEndpoint() - selection.lowerEndpoint());
        for (Token token : tokens().subList(selection.lowerEndpoint(), selection.upperEndpoint())) {
          copiedTokens.add(token.copy());
        }
        return new ClipboardContent() {
          @Override
          public boolean isSupported(ContentKind<?> kind) {
            return kind == TOKENS_CONTENT;
          }

          @Override
          public <T> T get(ContentKind<T> kind) {
            if (kind == TOKENS_CONTENT) {
              List<Token> result = new ArrayList<>(copiedTokens.size());
              for (Token token : copiedTokens) {
                result.add(token.copy());
              }
              return (T) Collections.unmodifiableList(result);
            }
            return null;
          }

          @Override
          public String toString() {
            try {
              return TokenUtil.getText(copiedTokens);
            } catch (UnsupportedOperationException e) {
              return super.toString();
            }
          }
        };
      }

      private boolean canCut() {
        return hasSelection();
      }

      private ClipboardContent cut() {
        ClipboardContent result = copy();
        clearSelection();
        return result;
      }
    };
  }