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