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; }
@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 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 void updatedMovedIntoEnd( final Document document, @NotNull final MoveInfo info, final int offset) { if (offset + 1 < document.getTextLength()) { final int line = document.getLineNumber(offset + 1); final LineRange toMove2 = info.toMove2; if (toMove2 == null) return; info.toMove2 = new LineRange( toMove2.startLine, Math.min(Math.max(line, toMove2.endLine), document.getLineCount() - 1)); } }
/** * Handles the mouse location click. * * @param loc the location that was clicked * @return true because the click has been handled */ @Override public boolean locationClicked(Location loc) { if (game.getTurn() instanceof SmartComputerCheckerPlayer) // ignore all clicks on CPU's turn { return true; } if (lastMove != null && lastMove.isJump() && lastMove.getPiece().canJump()) // locks selection onto jump-chaining piece { Piece lastPiece = lastMove.getPiece(); if (!loc.equals(lastPiece.getLocation()) && !lastPiece.getAllowedMoves().contains(loc)) // consumes irrelevant clicks { return true; } } if (getGrid().get(loc) != null && !(getGrid().get(loc) instanceof PieceTile)) { Piece p = getGrid().get(loc); if (pieceSelected) { game.undisplayMoves(playerPiece); } game.displayMoves(p); // selection and highlight available moves playerPiece = p; pieceSelected = true; } else if (pieceSelected && !playerPiece.getAllowedMoves().contains(loc)) { pieceSelected = false; game.undisplayMoves(playerPiece); // undo selection and highlight playerPiece = null; } else if (pieceSelected && playerPiece.getAllowedMoves().contains(loc)) { pieceSelected = false; game.undisplayMoves(playerPiece); // undo selection and highlight setPlayerLocation(loc); } return true; }
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; }
/** * Convert a chess move string to a Move object. The string may specify any combination of * piece/source/target/promotion information as long as it matches exactly one valid move. */ public static final Move stringToMove(Position pos, String strMove) { if (strMove.equals("--")) return new Move(0, 0, 0); strMove = strMove.replaceAll("=", ""); strMove = strMove.replaceAll("\\+", ""); strMove = strMove.replaceAll("#", ""); boolean wtm = pos.whiteMove; MoveInfo info = new MoveInfo(); boolean capture = false; if (strMove.equals("O-O") || strMove.equals("0-0") || strMove.equals("o-o")) { info.piece = wtm ? Piece.WKING : Piece.BKING; info.fromX = 4; info.toX = 6; info.fromY = info.toY = wtm ? 0 : 7; info.promPiece = Piece.EMPTY; } else if (strMove.equals("O-O-O") || strMove.equals("0-0-0") || strMove.equals("o-o-o")) { info.piece = wtm ? Piece.WKING : Piece.BKING; info.fromX = 4; info.toX = 2; info.fromY = info.toY = wtm ? 0 : 7; info.promPiece = Piece.EMPTY; } else { boolean atToSq = false; for (int i = 0; i < strMove.length(); i++) { char c = strMove.charAt(i); if (i == 0) { int piece = charToPiece(wtm, c); if (piece >= 0) { info.piece = piece; continue; } } int tmpX = c - 'a'; if ((tmpX >= 0) && (tmpX < 8)) { if (atToSq || (info.fromX >= 0)) info.toX = tmpX; else info.fromX = tmpX; } int tmpY = c - '1'; if ((tmpY >= 0) && (tmpY < 8)) { if (atToSq || (info.fromY >= 0)) info.toY = tmpY; else info.fromY = tmpY; } if ((c == 'x') || (c == '-')) { atToSq = true; if (c == 'x') capture = true; } if (i == strMove.length() - 1) { int promPiece = charToPiece(wtm, c); if (promPiece >= 0) { info.promPiece = promPiece; } } } if ((info.fromX >= 0) && (info.toX < 0)) { info.toX = info.fromX; info.fromX = -1; } if ((info.fromY >= 0) && (info.toY < 0)) { info.toY = info.fromY; info.fromY = -1; } if (info.piece < 0) { boolean haveAll = (info.fromX >= 0) && (info.fromY >= 0) && (info.toX >= 0) && (info.toY >= 0); if (!haveAll) info.piece = wtm ? Piece.WPAWN : Piece.BPAWN; } if (info.promPiece < 0) info.promPiece = Piece.EMPTY; } ArrayList<Move> moves = MoveGen.instance.pseudoLegalMoves(pos); moves = MoveGen.removeIllegal(pos, moves); ArrayList<Move> matches = new ArrayList<Move>(2); for (int i = 0; i < moves.size(); i++) { Move m = moves.get(i); int p = pos.getPiece(m.from); boolean match = true; if ((info.piece >= 0) && (info.piece != p)) match = false; if ((info.fromX >= 0) && (info.fromX != Position.getX(m.from))) match = false; if ((info.fromY >= 0) && (info.fromY != Position.getY(m.from))) match = false; if ((info.toX >= 0) && (info.toX != Position.getX(m.to))) match = false; if ((info.toY >= 0) && (info.toY != Position.getY(m.to))) match = false; if ((info.promPiece >= 0) && (info.promPiece != m.promoteTo)) match = false; if (match) { matches.add(m); } } int nMatches = matches.size(); if (nMatches == 0) return null; else if (nMatches == 1) return matches.get(0); if (!capture) return null; Move move = null; for (int i = 0; i < matches.size(); i++) { Move m = matches.get(i); int capt = pos.getPiece(m.to); if (capt != Piece.EMPTY) { if (move == null) move = m; else return null; } } return move; }
public boolean checkAvailable( @NotNull final Editor editor, @NotNull final PsiFile file, @NotNull final MoveInfo info, final boolean down) { if (!(file instanceof XmlFile)) { return false; } boolean available = super.checkAvailable(editor, file, info, down); if (!available) return false; // updated moved range end to cover multiline tag start final Document document = editor.getDocument(); int movedLineStart = document.getLineStartOffset(info.toMove.startLine); final int movedLineEnd = document.getLineEndOffset(info.toMove.endLine - 1); PsiElement movedEndElement = file.findElementAt(movedLineEnd); if (movedEndElement instanceof PsiWhiteSpace) movedEndElement = PsiTreeUtil.prevLeaf(movedEndElement); PsiElement movedStartElement = file.findElementAt(movedLineStart); if (movedStartElement instanceof PsiWhiteSpace) movedStartElement = PsiTreeUtil.nextLeaf(movedStartElement); if (movedEndElement == null || movedStartElement == null) return false; final PsiNamedElement namedParentAtEnd = PsiTreeUtil.getParentOfType(movedEndElement, PsiNamedElement.class); final PsiNamedElement namedParentAtStart = PsiTreeUtil.getParentOfType(movedStartElement, PsiNamedElement.class); final XmlText text = PsiTreeUtil.getParentOfType(movedStartElement, XmlText.class); final XmlText text2 = PsiTreeUtil.getParentOfType(movedEndElement, XmlText.class); // Let's do not care about injections for this mover if ((text != null && InjectedLanguageUtil.getInjectedPsiFiles(text) != null) || (text2 != null && InjectedLanguageUtil.getInjectedPsiFiles(text2) != null)) { return false; } XmlTag nearestTag = PsiTreeUtil.getParentOfType(movedStartElement, XmlTag.class); if (nearestTag != null && ("script".equals(nearestTag.getLocalName()) || (nearestTag instanceof HtmlTag && "script".equalsIgnoreCase(nearestTag.getLocalName())))) { return false; } PsiNamedElement movedParent = null; if (namedParentAtEnd == namedParentAtStart) movedParent = namedParentAtEnd; else if (namedParentAtEnd instanceof XmlAttribute && namedParentAtStart instanceof XmlTag && namedParentAtEnd.getParent() == namedParentAtStart) { movedParent = namedParentAtStart; } else if (namedParentAtStart instanceof XmlAttribute && namedParentAtEnd instanceof XmlTag && namedParentAtStart.getParent() == namedParentAtEnd) { movedParent = namedParentAtEnd; } if (movedParent == null) { return false; } final TextRange textRange = movedParent.getTextRange(); if (movedParent instanceof XmlTag) { final XmlTag tag = (XmlTag) movedParent; final TextRange valueRange = tag.getValue().getTextRange(); final int valueStart = valueRange.getStartOffset(); if (movedLineStart < valueStart && valueStart + 1 < document.getTextLength()) { movedLineStart = updateMovedRegionEnd(document, movedLineStart, valueStart + 1, info, down); } if (movedLineStart < valueStart) { movedLineStart = updatedMovedRegionStart( document, movedLineStart, tag.getTextRange().getStartOffset(), info, down); } } else if (movedParent instanceof XmlAttribute) { final int endOffset = textRange.getEndOffset() + 1; if (endOffset < document.getTextLength()) movedLineStart = updateMovedRegionEnd(document, movedLineStart, endOffset, info, down); movedLineStart = updatedMovedRegionStart(document, movedLineStart, textRange.getStartOffset(), info, down); } final TextRange moveDestinationRange = new TextRange( document.getLineStartOffset(info.toMove2.startLine), document.getLineStartOffset(info.toMove2.endLine)); if (movedParent instanceof XmlAttribute) { final XmlTag parent = ((XmlAttribute) movedParent).getParent(); if (parent != null) { final TextRange valueRange = parent.getValue().getTextRange(); // Do not move attributes out of tags if ((down && moveDestinationRange.getEndOffset() >= valueRange.getStartOffset()) || (!down && moveDestinationRange.getStartOffset() <= parent.getTextRange().getStartOffset())) { info.toMove2 = null; } } } if (down) { PsiElement updatedElement = file.findElementAt(moveDestinationRange.getEndOffset()); if (updatedElement instanceof PsiWhiteSpace) updatedElement = PsiTreeUtil.prevLeaf(updatedElement); if (updatedElement != null) { final PsiNamedElement namedParent = PsiTreeUtil.getParentOfType(updatedElement, movedParent.getClass()); if (namedParent instanceof XmlTag) { final XmlTag tag = (XmlTag) namedParent; final int offset = tag.isEmpty() ? tag.getTextRange().getStartOffset() : tag.getValue().getTextRange().getStartOffset(); updatedMovedIntoEnd(document, info, offset); } else if (namedParent instanceof XmlAttribute) { updatedMovedIntoEnd(document, info, namedParent.getTextRange().getEndOffset()); } } } else { PsiElement updatedElement = file.findElementAt(moveDestinationRange.getStartOffset()); if (updatedElement instanceof PsiWhiteSpace) updatedElement = PsiTreeUtil.nextLeaf(updatedElement); if (updatedElement != null) { final PsiNamedElement namedParent = PsiTreeUtil.getParentOfType(updatedElement, movedParent.getClass()); if (namedParent instanceof XmlTag) { final XmlTag tag = (XmlTag) namedParent; final TextRange tagValueRange = tag.getValue().getTextRange(); // We need to update destination range to jump over tag start final XmlTag[] subtags = tag.getSubTags(); if ((tagValueRange.contains(movedLineStart) && subtags.length > 0 && subtags[0] == movedParent) || (tagValueRange.getLength() == 0 && tag.getTextRange().intersects(moveDestinationRange))) { final int line = document.getLineNumber(tag.getTextRange().getStartOffset()); final LineRange toMove2 = info.toMove2; info.toMove2 = new LineRange(Math.min(line, toMove2.startLine), toMove2.endLine); } } else if (namedParent instanceof XmlAttribute) { final int line = document.getLineNumber(namedParent.getTextRange().getStartOffset()); final LineRange toMove2 = info.toMove2; info.toMove2 = new LineRange(Math.min(line, toMove2.startLine), toMove2.endLine); } } } return true; }