@Override
  public boolean checkAvailable(
      @NotNull final Editor editor,
      @NotNull final PsiFile file,
      @NotNull final MoveInfo info,
      final boolean down) {
    // if (!(file instanceof PsiJavaFile)) return false;
    final boolean available = super.checkAvailable(editor, file, info, down);
    if (!available) return false;
    LineRange range = info.toMove;

    range = expandLineRangeToCoverPsiElements(range, editor, file);
    if (range == null) return false;
    info.toMove = range;
    final int startOffset = editor.logicalPositionToOffset(new LogicalPosition(range.startLine, 0));
    final int endOffset = editor.logicalPositionToOffset(new LogicalPosition(range.endLine, 0));
    final PsiElement[] statements =
        CodeInsightUtil.findStatementsInRange(file, startOffset, endOffset);
    if (statements.length == 0) return false;
    range.firstElement = statements[0];
    range.lastElement = statements[statements.length - 1];

    if (!checkMovingInsideOutside(file, editor, range, info, down)) {
      info.toMove2 = null;
      return true;
    }
    return true;
  }
Exemple #2
0
  private static BraceStatus checkForMovableDownClosingBrace(
      @NotNull PsiElement closingBrace,
      @NotNull PsiElement block,
      @NotNull Editor editor,
      @NotNull MoveInfo info) {
    PsiElement current = block;
    PsiElement nextElement = null;
    PsiElement nextExpression = null;
    do {
      PsiElement sibling = firstNonWhiteElement(current.getNextSibling(), true);
      if (sibling != null && nextElement == null) {
        nextElement = sibling;
      }

      if (sibling instanceof JetExpression) {
        nextExpression = sibling;
        break;
      }

      current = current.getParent();
    } while (current != null && !(PsiTreeUtil.instanceOf(current, BLOCKLIKE_ELEMENT_CLASSES)));

    if (nextExpression == null) return BraceStatus.NOT_MOVABLE;

    Document doc = editor.getDocument();

    info.toMove = new LineRange(closingBrace, closingBrace, doc);
    info.toMove2 = new LineRange(nextElement, nextExpression);
    info.indentSource = true;

    return BraceStatus.MOVABLE;
  }
  private boolean checkMovingInsideOutside(
      PsiFile file,
      final Editor editor,
      LineRange range,
      @NotNull final MoveInfo info,
      final boolean down) {
    final int offset = editor.getCaretModel().getOffset();

    PsiElement elementAtOffset = file.getViewProvider().findElementAt(offset, StdLanguages.JAVA);
    if (elementAtOffset == null) return false;

    PsiElement guard = elementAtOffset;
    do {
      guard =
          PsiTreeUtil.getParentOfType(
              guard, PsiMethod.class, PsiClassInitializer.class, PsiClass.class, PsiComment.class);
    } while (guard instanceof PsiAnonymousClass);

    PsiElement brace = itIsTheClosingCurlyBraceWeAreMoving(file, editor);
    if (brace != null) {
      int line = editor.getDocument().getLineNumber(offset);
      final LineRange toMove = new LineRange(line, line + 1);
      toMove.firstElement = toMove.lastElement = brace;
      info.toMove = toMove;
    }

    // cannot move in/outside method/class/initializer/comment
    if (!calcInsertOffset(file, editor, info.toMove, info, down)) return false;
    int insertOffset =
        down
            ? getLineStartSafeOffset(editor.getDocument(), info.toMove2.endLine)
            : editor.getDocument().getLineStartOffset(info.toMove2.startLine);
    PsiElement elementAtInsertOffset =
        file.getViewProvider().findElementAt(insertOffset, StdLanguages.JAVA);
    PsiElement newGuard = elementAtInsertOffset;
    do {
      newGuard =
          PsiTreeUtil.getParentOfType(
              newGuard,
              PsiMethod.class,
              PsiClassInitializer.class,
              PsiClass.class,
              PsiComment.class);
    } while (newGuard instanceof PsiAnonymousClass);

    if (brace != null
        && PsiTreeUtil.getParentOfType(brace, PsiCodeBlock.class, false)
            != PsiTreeUtil.getParentOfType(elementAtInsertOffset, PsiCodeBlock.class, false)) {
      info.indentSource = true;
    }
    if (newGuard == guard && isInside(insertOffset, newGuard) == isInside(offset, guard))
      return true;

    // moving in/out nested class is OK
    if (guard instanceof PsiClass && guard.getParent() instanceof PsiClass) return true;
    if (newGuard instanceof PsiClass && newGuard.getParent() instanceof PsiClass) return true;

    return false;
  }
Exemple #4
0
  @Override
  public boolean checkAvailable(
      @NotNull Editor editor, @NotNull PsiFile file, @NotNull MoveInfo info, boolean down) {
    parametersOrArgsToMove = null;

    if (!super.checkAvailable(editor, file, info, down)) return false;

    switch (checkForMovableClosingBrace(editor, file, info, down)) {
      case NOT_MOVABLE:
        {
          info.toMove2 = null;
          return true;
        }
      case MOVABLE:
        return true;
      default:
        break;
    }

    LineRange oldRange = info.toMove;

    Pair<PsiElement, PsiElement> psiRange = getElementRange(editor, file, oldRange);
    if (psiRange == null) return false;

    //noinspection unchecked
    PsiElement firstElement = getMovableElement(psiRange.getFirst(), false);
    PsiElement lastElement = getMovableElement(psiRange.getSecond(), true);

    if (firstElement == null || lastElement == null) return false;

    if (isForbiddenMove(firstElement, down) || isForbiddenMove(lastElement, down)) {
      info.toMove2 = null;
      return true;
    }

    if ((firstElement instanceof JetParameter || firstElement instanceof JetValueArgument)
        && PsiTreeUtil.isAncestor(lastElement, firstElement, false)) {
      lastElement = firstElement;
    }

    LineRange sourceRange = getSourceRange(firstElement, lastElement, editor, oldRange);
    if (sourceRange == null) return false;

    PsiElement sibling =
        getLastNonWhiteSiblingInLine(adjustSibling(editor, sourceRange, info, down), editor, down);

    // Either reached last sibling, or jumped over multi-line whitespace
    if (sibling == null) return true;

    info.toMove = sourceRange;
    info.toMove2 = getTargetRange(editor, sourceRange.firstElement, sibling, down);
    return true;
  }
  private boolean calcInsertOffset(
      PsiFile file,
      final Editor editor,
      LineRange range,
      @NotNull final MoveInfo info,
      final boolean down) {
    int line = down ? range.endLine + 1 : range.startLine - 1;
    int startLine = down ? range.endLine : range.startLine - 1;
    if (line < 0 || startLine < 0) return false;
    while (true) {
      final int offset = editor.logicalPositionToOffset(new LogicalPosition(line, 0));
      PsiElement element = firstNonWhiteElement(offset, file, true);

      while (element != null && !(element instanceof PsiFile)) {
        if (!element.getTextRange().grown(-1).shiftRight(1).contains(offset)) {
          PsiElement elementToSurround = null;
          boolean found = false;
          if ((element instanceof PsiStatement || element instanceof PsiComment)
              && statementCanBePlacedAlong(element)) {
            found = true;
            if (!(element.getParent() instanceof PsiCodeBlock)) {
              elementToSurround = element;
            }
          } else if (element instanceof PsiJavaToken
              && ((PsiJavaToken) element).getTokenType() == JavaTokenType.RBRACE
              && element.getParent() instanceof PsiCodeBlock) {
            // before code block closing brace
            found = true;
          }
          if (found) {
            statementToSurroundWithCodeBlock = elementToSurround;
            info.toMove = range;
            int endLine = line;
            if (startLine > endLine) {
              int tmp = endLine;
              endLine = startLine;
              startLine = tmp;
            }

            info.toMove2 =
                down ? new LineRange(startLine, endLine) : new LineRange(startLine, endLine + 1);
            return true;
          }
        }
        element = element.getParent();
      }
      line += down ? 1 : -1;
      if (line == 0 || line >= editor.getDocument().getLineCount()) {
        return false;
      }
    }
  }
Exemple #6
0
  protected static PsiElement adjustSibling(
      @NotNull Editor editor,
      @NotNull LineRange sourceRange,
      @NotNull MoveInfo info,
      boolean down) {
    PsiElement element = down ? sourceRange.lastElement : sourceRange.firstElement;
    PsiElement sibling = down ? element.getNextSibling() : element.getPrevSibling();

    PsiElement whiteSpaceTestSubject = sibling;
    if (sibling == null) {
      PsiElement parent = element.getParent();
      if (parent != null && isBracelessBlock(parent)) {
        whiteSpaceTestSubject = down ? parent.getNextSibling() : parent.getPrevSibling();
      }
    }

    if (whiteSpaceTestSubject instanceof PsiWhiteSpace) {
      if (getElementLineCount(whiteSpaceTestSubject, editor) > 1) {
        int nearLine = down ? sourceRange.endLine : sourceRange.startLine - 1;

        info.toMove = sourceRange;
        info.toMove2 = new LineRange(nearLine, nearLine + 1);
        info.indentTarget = false;

        return null;
      }

      if (sibling != null) {
        sibling = firstNonWhiteElement(sibling, down);
      }
    }

    if (sibling == null) {
      JetCallExpression callExpression =
          PsiTreeUtil.getParentOfType(element, JetCallExpression.class);
      if (callExpression != null) {
        JetBlockExpression dslBlock = getDSLLambdaBlock(callExpression, down);
        if (PsiTreeUtil.isAncestor(dslBlock, element, false)) {
          //noinspection ConstantConditions
          PsiElement blockParent = dslBlock.getParent();
          return down
              ? JetPsiUtil.findChildByType(blockParent, JetTokens.RBRACE)
              : JetPsiUtil.findChildByType(blockParent, JetTokens.LBRACE);
        }
      }

      info.toMove2 = null;
      return null;
    }

    return sibling;
  }
  public boolean checkAvailable(
      @NotNull final Editor editor,
      @NotNull final PsiFile file,
      @NotNull final MoveInfo info,
      final boolean down) {
    LineRange range = StatementUpDownMover.getLineRangeFromSelection(editor);

    final int maxLine = editor.offsetToLogicalPosition(editor.getDocument().getTextLength()).line;
    if (range.startLine == 0 && !down) return false;
    if (range.endLine >= maxLine && down) return false;

    int nearLine = down ? range.endLine : range.startLine - 1;
    info.toMove = range;
    info.toMove2 = new LineRange(nearLine, nearLine + 1);

    return true;
  }
  private void surroundWithCodeBlock(@NotNull final MoveInfo info, final boolean down) {
    try {
      final Document document =
          PsiDocumentManager.getInstance(statementToSurroundWithCodeBlock.getProject())
              .getDocument(statementToSurroundWithCodeBlock.getContainingFile());
      int startOffset = document.getLineStartOffset(info.toMove.startLine);
      int endOffset = getLineStartSafeOffset(document, info.toMove.endLine);
      if (document.getText().charAt(endOffset - 1) == '\n') endOffset--;
      final RangeMarker lineRangeMarker = document.createRangeMarker(startOffset, endOffset);

      final PsiElementFactory factory =
          JavaPsiFacade.getInstance(statementToSurroundWithCodeBlock.getProject())
              .getElementFactory();
      PsiCodeBlock codeBlock = factory.createCodeBlock();
      codeBlock.add(statementToSurroundWithCodeBlock);
      final PsiBlockStatement blockStatement =
          (PsiBlockStatement)
              factory.createStatementFromText("{}", statementToSurroundWithCodeBlock);
      blockStatement.getCodeBlock().replace(codeBlock);
      PsiBlockStatement newStatement =
          (PsiBlockStatement) statementToSurroundWithCodeBlock.replace(blockStatement);
      newStatement = CodeInsightUtilBase.forcePsiPostprocessAndRestoreElement(newStatement);
      info.toMove =
          new LineRange(
              document.getLineNumber(lineRangeMarker.getStartOffset()),
              document.getLineNumber(lineRangeMarker.getEndOffset()) + 1);
      PsiCodeBlock newCodeBlock = newStatement.getCodeBlock();
      if (down) {
        PsiElement blockChild = firstNonWhiteElement(newCodeBlock.getFirstBodyElement(), true);
        if (blockChild == null) blockChild = newCodeBlock.getRBrace();
        info.toMove2 =
            new LineRange(
                info.toMove2
                    .startLine, // document.getLineNumber(newCodeBlock.getParent().getTextRange().getStartOffset()),
                document.getLineNumber(blockChild.getTextRange().getStartOffset()));
      } else {
        int start =
            document.getLineNumber(newCodeBlock.getRBrace().getTextRange().getStartOffset());
        int end = info.toMove.startLine;
        if (start > end) end = start;
        info.toMove2 = new LineRange(start, end);
      }
    } catch (IncorrectOperationException e) {
      LOG.error(e);
    }
  }
Exemple #9
0
  private static BraceStatus checkForMovableUpClosingBrace(
      @NotNull PsiElement closingBrace,
      PsiElement block,
      @NotNull Editor editor,
      @NotNull MoveInfo info) {
    //noinspection unchecked
    PsiElement prev = JetPsiUtil.getLastChildByType(block, JetExpression.class);
    if (prev == null) return BraceStatus.NOT_MOVABLE;

    Document doc = editor.getDocument();

    info.toMove = new LineRange(closingBrace, closingBrace, doc);
    info.toMove2 = new LineRange(prev, prev, doc);
    info.indentSource = true;

    return BraceStatus.MOVABLE;
  }
  private int updatedMovedRegionStart(
      final Document document,
      int movedLineStart,
      final int offset,
      @NotNull final MoveInfo info,
      final boolean down) {
    final int line = document.getLineNumber(offset);
    final LineRange toMove = info.toMove;
    int delta = toMove.startLine - line;
    info.toMove = new LineRange(Math.min(line, toMove.startLine), toMove.endLine);

    // update moved range
    if (delta > 0 && !down) {
      final LineRange toMove2 = info.toMove2;
      info.toMove2 = new LineRange(toMove2.startLine - delta, toMove2.endLine - delta);
      movedLineStart = document.getLineStartOffset(toMove.startLine);
    }
    return movedLineStart;
  }
  private int updateMovedRegionEnd(
      final Document document,
      int movedLineStart,
      final int valueStart,
      @NotNull final MoveInfo info,
      final boolean down) {
    final int line = document.getLineNumber(valueStart);
    final LineRange toMove = info.toMove;
    int delta = line - toMove.endLine;
    info.toMove = new LineRange(toMove.startLine, Math.max(line, toMove.endLine));

    // update moved range
    if (delta > 0 && down) {
      final LineRange toMove2 = info.toMove2;
      info.toMove2 =
          new LineRange(
              toMove2.startLine + delta,
              Math.min(toMove2.endLine + delta, document.getLineCount() - 1));
      movedLineStart = document.getLineStartOffset(toMove.startLine);
    }
    return movedLineStart;
  }