/** deletes the selected text */ public void delete(final TextSelection selection) { final CursorPosition from = selection.from(); final CursorPosition to = selection.to(); final BlockToLineMapping fromMapping = findBlockFor(from.getLine()); final int fromBlock = fromMapping.index; final int fromLine = fromMapping.line; final int fromCharacter = from.getCharacter(); final BlockToLineMapping toMapping = findBlockFor(to.getLine()); final int toBlock = toMapping.index; final int toLine = toMapping.line; final int toCharacter = to.getCharacter(); if (fromBlock == toBlock) { final TextBlock block = (TextBlock) blocks.elementAt(fromBlock); block.delete(fromLine, fromCharacter, toLine, toCharacter); } else { TextBlock block = (TextBlock) blocks.elementAt(toBlock); block.deleteTo(toLine, toCharacter); block = (TextBlock) blocks.elementAt(fromBlock); block.deleteFrom(fromLine, fromCharacter); fromMapping.textBlock.join(toMapping.textBlock); blocks.removeElementAt(toMapping.index); for (int i = fromBlock + 1; i < toBlock; i++) { blocks.removeElementAt(i); } } }
private static void assertBeforeCommit( Document document, PsiFile file, TextBlock textBlock, CharSequence chars, String oldPsiText, FileElement myTreeElementBeingReparsedSoItWontBeCollected) { int startOffset = textBlock.getStartOffset(); int psiEndOffset = textBlock.getPsiEndOffset(); if (oldPsiText != null) { @NonNls String msg = "PSI/document inconsistency before reparse: "; if (startOffset >= oldPsiText.length()) { msg += "startOffset=" + oldPsiText + " while text length is " + oldPsiText.length() + "; "; startOffset = oldPsiText.length(); } String psiPrefix = oldPsiText.substring(0, startOffset); String docPrefix = chars.subSequence(0, startOffset).toString(); String psiSuffix = oldPsiText.substring(psiEndOffset); String docSuffix = chars.subSequence(textBlock.getTextEndOffset(), chars.length()).toString(); if (!psiPrefix.equals(docPrefix) || !psiSuffix.equals(docSuffix)) { if (!psiPrefix.equals(docPrefix)) { msg = msg + "psiPrefix=" + psiPrefix + "; docPrefix=" + docPrefix + ";"; } if (!psiSuffix.equals(docSuffix)) { msg = msg + "psiSuffix=" + psiSuffix + "; docSuffix=" + docSuffix + ";"; } throw new AssertionError(msg); } } else if (document.getTextLength() - textBlock.getTextEndOffset() != myTreeElementBeingReparsedSoItWontBeCollected.getTextLength() - psiEndOffset) { throw new AssertionError("PSI/document inconsistency before reparse: file=" + file); } }
public TextDocument clone() { final List<TextBlock> list = new ArrayList<TextBlock>(textBlocks.size()); for (TextBlock tb : textBlocks) { list.add(tb.clone()); } return new TextDocument(title, list); }
/** * Returns detailed debugging information about the contained {@link TextBlock}s. * * @return Debug information. */ public String debugString() { StringBuilder sb = new StringBuilder(); for (TextBlock tb : getTextBlocks()) { sb.append(tb.toString()); sb.append('\n'); } return sb.toString(); }
private void insertLetterBeforeNonWord(TextBlock tb, char c) { TextBlock bpr = tb.previousTextBlock(); if (bpr instanceof WordBlock) { insertLetterInWord(bpr, c, bpr.textLength()); } else { addNewWordBlockAfter(bpr, c); } }
private void addNewPuncBlockAfter(TextBlock bpr, char c) { PunctuationBlock wb = new PunctuationBlock(); wb.setText("" + c); Block bnx = bpr.next(); bpr.setNext(wb); wb.setNext(bnx); caretBlock = wb; caretPos = 1; }
private void insertPuncBeforeNonPunc(TextBlock tb, char c) { TextBlock bpr = tb.previousTextBlock(); if (bpr instanceof PunctuationBlock) { insertPuncInPunc(bpr, c, bpr.textLength()); } else { addNewPuncBlockAfter(bpr, c); } }
@Override public void drawU(UGraphic ug, double x, double y) { final StringBounder stringBounder = ug.getStringBounder(); final double heightNum = numText.calculateDimension(stringBounder).getHeight(); final double deltaY = calculateDimension(stringBounder).getHeight() - heightNum; numText.drawU(ug, x, y + deltaY / 2.0); super.drawU(ug, x + getNumberWithAndMargin(stringBounder), y); }
@Override public void drawTOBEREMOVED(ColorMapper colorMapper, Graphics2D g2d, double x, double y) { final StringBounder stringBounder = StringBounderUtils.asStringBounder(g2d); final double heightNum = numText.calculateDimension(stringBounder).getHeight(); final double deltaY = calculateDimension(stringBounder).getHeight() - heightNum; numText.drawTOBEREMOVED(colorMapper, g2d, x, y + deltaY / 2.0); super.drawTOBEREMOVED(colorMapper, g2d, x + getNumberWithAndMargin(stringBounder), y); }
/** * Checks if the specified position intersects with a CPP comment. * * @param startLineNo the starting line number * @param startColNo the starting column number * @param endLineNo the ending line number * @param endColNo the ending column number * @return true if the positions intersects with a CPP comment. */ private boolean hasIntersectionWithCppComment( int startLineNo, int startColNo, int endLineNo, int endColNo) { // Check CPP comments (line searching is possible) for (int lineNumber = startLineNo; lineNumber <= endLineNo; lineNumber++) { final TextBlock comment = cppComments.get(lineNumber); if (comment != null && comment.intersects(startLineNo, startColNo, endLineNo, endColNo)) { return true; } } return false; }
/** * returns the entire text of the content, with a newline between each block (but not after the * final block. */ public String getText() { final StringBuffer content = new StringBuffer(); final Enumeration e = blocks.elements(); while (e.hasMoreElements()) { final TextBlock block = (TextBlock) e.nextElement(); if (content.length() > 0) { content.append("\n"); } content.append(block.getText()); } return content.toString(); }
/** * Checks if the specified position intersects with a C comment. * * @param startLineNo the starting line number * @param startColNo the starting column number * @param endLineNo the ending line number * @param endColNo the ending column number * @return true if the positions intersects with a C comment. */ private boolean hasIntersectionWithCComment( int startLineNo, int startColNo, int endLineNo, int endColNo) { // Check C comments (all comments should be checked) final Collection<List<TextBlock>> values = clangComments.values(); for (final List<TextBlock> row : values) { for (final TextBlock comment : row) { if (comment.intersects(startLineNo, startColNo, endLineNo, endColNo)) { return true; } } } return false; }
public void deletBackwards() { if (caretPos == 0) { TextBlock tb = caretBlock.previousTextBlock(); if (tb == null) { return; } else { caretBlock = tb; caretPos = caretBlock.textLength(); } } if (caretBlock.textLength() == 1) { TextBlock tb = caretBlock.previousTextBlock(); int newPos = tb.textLength(); caretBlock.remove(); if (tb == null) { caretBlock = textBoard.firstTextBlock(); caretPos = 0; } else { caretBlock = tb; caretPos = newPos; } } else { caretBlock.deleteCharBefore(caretPos); caretPos -= 1; } textBoard.repaint(); }
@Override public void documentChanged(DocumentEvent event) { final Document document = event.getDocument(); final FileViewProvider viewProvider = getCachedViewProvider(document); if (viewProvider == null) return; if (!isRelevant(viewProvider)) return; ApplicationManager.getApplication().assertWriteAccessAllowed(); final List<PsiFile> files = viewProvider.getAllFiles(); boolean commitNecessary = true; for (PsiFile file : files) { mySmartPointerManager.unfastenBelts(file, event.getOffset()); final TextBlock textBlock = TextBlock.get(file); if (textBlock.isLocked()) { commitNecessary = false; continue; } textBlock.documentChanged(event); assert file instanceof PsiFileImpl || "mock.file".equals(file.getName()) && ApplicationManager.getApplication().isUnitTestMode() : event + "; file=" + file + "; allFiles=" + files + "; viewProvider=" + viewProvider; } boolean forceCommit = ApplicationManager.getApplication().hasWriteAction(ExternalChangeAction.class) && (SystemProperties.getBooleanProperty("idea.force.commit.on.external.change", false) || ApplicationManager.getApplication().isHeadlessEnvironment()); // Consider that it's worth to perform complete re-parse instead of merge if the whole document // text is replaced and // current document lines number is roughly above 5000. This makes sense in situations when // external change is performed // for the huge file (that causes the whole document to be reloaded and 'merge' way takes a // while to complete). if (event.isWholeTextReplaced() && document.getTextLength() > 100000) { document.putUserData(BlockSupport.DO_NOT_REPARSE_INCREMENTALLY, Boolean.TRUE); } if (commitNecessary) { myUncommittedDocuments.add(document); if (forceCommit) { commitDocument(document); } else if (!((DocumentEx) document).isInBulkUpdate()) { myDocumentCommitProcessor.commitAsynchronously(myProject, document, event); } } }
private void insertPuncInNonPunc(TextBlock tb, char c, int cp) { PunctuationBlock wb = new PunctuationBlock(); wb.setText("" + c); tb.insert(wb, cp); caretBlock = wb; caretPos = 1; }
private void insertLetterInNonWord(TextBlock tb, char c, int cp) { WordBlock wb = new WordBlock(); wb.setText("" + c); tb.insert(wb, cp); caretBlock = wb; caretPos = 1; }
@Override public void beforeDocumentChange(DocumentEvent event) { final Document document = event.getDocument(); final FileViewProvider viewProvider = getCachedViewProvider(document); if (viewProvider == null) return; if (!isRelevant(viewProvider)) return; VirtualFile virtualFile = viewProvider.getVirtualFile(); if (virtualFile.getFileType().isBinary()) return; final List<PsiFile> files = viewProvider.getAllFiles(); PsiFile psiCause = null; for (PsiFile file : files) { mySmartPointerManager.fastenBelts(file, event.getOffset(), null); if (TextBlock.get(file).isLocked()) { psiCause = file; } } if (psiCause == null) { beforeDocumentChangeOnUnlockedDocument(viewProvider); } ((SingleRootFileViewProvider) viewProvider).beforeDocumentChanged(psiCause); }
@Override public Dimension2D calculateDimension(StringBounder stringBounder) { final double widthNum = getNumberWithAndMargin(stringBounder); final double heightNum = numText.calculateDimension(stringBounder).getHeight(); final Dimension2D dim = super.calculateDimension(stringBounder); return new Dimension2DDouble(dim.getWidth() + widthNum, Math.max(heightNum, dim.getHeight())); }
public void caretRight() { if (caretBlock == null) { return; } if (caretPos < caretBlock.textLength()) { caretPos += 1; } else { TextBlock tb = caretBlock.nextTextBlock(); if (tb == null) { } else { caretBlock = tb; caretPos = 1; } } textBoard.repaint(); }
@Override public boolean apply(@Nullable Duplicate input) { if (input instanceof InnerDuplicate) { checkArgument( !original.equals(input.getTextBlock()), "TextBlock of an InnerDuplicate can not be the original TextBlock"); } return true; }
private void insertPuncAfterNonPunc(TextBlock tb, char c) { TextBlock bnx = tb.nextTextBlock(); if (bnx instanceof PunctuationBlock) { insertPuncInPunc(bnx, c, 0); } else { addNewPuncBlockAfter(tb, c); } }
public void caretLeft() { if (caretBlock == null) { return; } if (caretPos > 0) { caretPos -= 1; } else { TextBlock tb = caretBlock.previousTextBlock(); if (tb == null) { } else { caretBlock = tb; caretPos = caretBlock.textLength() - 1; } } textBoard.repaint(); }
/** * Returns the {@link TextDocument}'s content, non-content or both * * @param includeContent Whether to include TextBlocks marked as "content". * @param includeNonContent Whether to include TextBlocks marked as "non-content". * @return The text. */ public String getText(boolean includeContent, boolean includeNonContent) { StringBuilder sb = new StringBuilder(); LOOP: for (TextBlock block : getTextBlocks()) { if (block.isContent()) { if (!includeContent) { continue LOOP; } } else { if (!includeNonContent) { continue LOOP; } } sb.append(block.getText()); sb.append('\n'); } return sb.toString(); }
private void insertLetterAfterNonWord(TextBlock tb, char c) { TextBlock bnx = tb.nextTextBlock(); if (bnx instanceof WordBlock) { insertLetterInWord(bnx, c, 0); } else { addNewWordBlockAfter(tb, c); } }
private BlockToLineMapping findBlockFor(final int line) { if (line < 0) { throw new IllegalArgumentException("Line must be greater than, or equal to, zero: " + line); } int lineWithinBlock = line; for (int i = 0; i < blocks.size(); i++) { final TextBlock block = (TextBlock) blocks.elementAt(i); final int noLines = block.noLines(); if (lineWithinBlock < noLines) { UI_LOG.debug("block " + i + ", line " + lineWithinBlock); return new BlockToLineMapping(i, block, lineWithinBlock); } lineWithinBlock -= noLines; } return null; // throw new IllegalArgumentException("line number not valid " + line); }
@Override public boolean equals(@Nullable Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } Duplication that = (Duplication) o; return original.equals(that.original) && duplicates.equals(that.duplicates); }
private void doSync( @NotNull final PsiTreeChangeEvent event, boolean force, @NotNull final DocSyncAction syncAction) { if (!toProcessPsiEvent()) return; final PsiFile psiFile = event.getFile(); if (psiFile == null || psiFile.getNode() == null) return; final DocumentEx document = (DocumentEx) myPsiDocumentManager.getCachedDocument(psiFile); if (document == null || document instanceof DocumentWindow) return; if (!force && getTransaction(document) == null) { return; } TextBlock textBlock = TextBlock.get(psiFile); if (!textBlock.isEmpty()) { throw new IllegalStateException("Attempt to modify PSI for non-committed Document!"); } textBlock.performAtomically( new Runnable() { @Override public void run() { syncAction.syncDocument(document, (PsiTreeChangeEventImpl) event); } }); final boolean insideTransaction = myTransactionsMap.containsKey(document); if (!insideTransaction) { document.setModificationStamp(psiFile.getViewProvider().getModificationStamp()); if (LOG.isDebugEnabled()) { PsiDocumentManagerBase.checkConsistency(psiFile, document); } } psiFile.getViewProvider().contentsSynchronized(); }
private void insertPunctuation(char c) { if (caretBlock instanceof PunctuationBlock) { insertPuncInPunc(caretBlock, c, caretPos); } else { if (caretPos == 0) { insertPuncBeforeNonPunc(caretBlock, c); } else if (caretPos == caretBlock.textLength()) { insertPuncAfterNonPunc(caretBlock, c); } else { insertPuncInNonPunc(caretBlock, c, caretPos); } } }
private void insertLetter(char c) { if (caretBlock instanceof WordBlock) { insertLetterInWord(caretBlock, c, caretPos); } else { if (caretPos == 0) { insertLetterBeforeNonWord(caretBlock, c); } else if (caretPos == caretBlock.textLength()) { insertLetterAfterNonWord(caretBlock, c); } else { insertLetterInNonWord(caretBlock, c, caretPos); } } }
private void newline() { if (caretPos == 0) { TextBlock tbp = caretBlock.previousTextBlock(); if (tbp != null) { tbp.newlineAfter(); } } else if (caretPos == caretBlock.textLength()) { caretBlock.newlineAfter(); caretBlock = caretBlock.nextTextBlock(); caretPos = 1; } else { caretBlock.insertNewline(caretPos); caretBlock = caretBlock.nextTextBlock(); caretPos = 1; } }