private void paintWhitespace( Graphics2D g, CharSequence text, float x, int y, int start, int end, EditorImpl.LineWhitespacePaintingStrategy whitespacePaintingStrategy, VisualLineFragmentsIterator.Fragment fragment) { g.setColor(myEditor.getColorsScheme().getColor(EditorColors.WHITESPACES_COLOR)); boolean isRtl = fragment.isRtl(); int baseStartOffset = fragment.getStartOffset(); int startOffset = isRtl ? baseStartOffset - start : baseStartOffset + start; for (int i = start; i < end; i++) { int charOffset = isRtl ? baseStartOffset - i - 1 : baseStartOffset + i; char c = text.charAt(charOffset); if (" \t\u3000".indexOf(c) >= 0 && whitespacePaintingStrategy.showWhitespaceAtOffset(charOffset)) { int startX = (int) fragment.offsetToX( x, startOffset, isRtl ? baseStartOffset - i : baseStartOffset + i); int endX = (int) fragment.offsetToX( x, startOffset, isRtl ? baseStartOffset - i - 1 : baseStartOffset + i + 1); if (c == ' ') { g.fillRect((startX + endX) / 2, y, 1, 1); } else if (c == '\t') { endX -= myView.getPlainSpaceWidth() / 4; int height = myView.getCharHeight(); int halfHeight = height / 2; int mid = y - halfHeight; int top = y - height; UIUtil.drawLine(g, startX, mid, endX, mid); UIUtil.drawLine(g, endX, y, endX, top); g.fillPolygon( new int[] {endX - halfHeight, endX - halfHeight, endX}, new int[] {y, y - height, y - halfHeight}, 3); } else if (c == '\u3000') { // ideographic space final int charHeight = myView.getCharHeight(); g.drawRect(startX + 2, y - charHeight, endX - startX - 4, charHeight); } } } }
public static boolean checkConsistency(PsiFile psiFile, Document document) { // todo hack if (psiFile.getVirtualFile() == null) return true; CharSequence editorText = document.getCharsSequence(); int documentLength = document.getTextLength(); if (psiFile.textMatches(editorText)) { LOG.assertTrue(psiFile.getTextLength() == documentLength); return true; } char[] fileText = psiFile.textToCharArray(); @SuppressWarnings({"NonConstantStringShouldBeStringBuffer"}) @NonNls String error = "File '" + psiFile.getName() + "' text mismatch after reparse. " + "File length=" + fileText.length + "; Doc length=" + documentLength + "\n"; int i = 0; for (; i < documentLength; i++) { if (i >= fileText.length) { error += "editorText.length > psiText.length i=" + i + "\n"; break; } if (i >= editorText.length()) { error += "editorText.length > psiText.length i=" + i + "\n"; break; } if (editorText.charAt(i) != fileText[i]) { error += "first unequal char i=" + i + "\n"; break; } } // error += "*********************************************" + "\n"; // if (i <= 500){ // error += "Equal part:" + editorText.subSequence(0, i) + "\n"; // } // else{ // error += "Equal part start:\n" + editorText.subSequence(0, 200) + "\n"; // error += "................................................" + "\n"; // error += "................................................" + "\n"; // error += "................................................" + "\n"; // error += "Equal part end:\n" + editorText.subSequence(i - 200, i) + "\n"; // } error += "*********************************************" + "\n"; error += "Editor Text tail:(" + (documentLength - i) + ")\n"; // + editorText.subSequence(i, Math.min(i + 300, documentLength)) + "\n"; error += "*********************************************" + "\n"; error += "Psi Text tail:(" + (fileText.length - i) + ")\n"; error += "*********************************************" + "\n"; if (document instanceof DocumentWindow) { error += "doc: '" + document.getText() + "'\n"; error += "psi: '" + psiFile.getText() + "'\n"; error += "ast: '" + psiFile.getNode().getText() + "'\n"; error += psiFile.getLanguage() + "\n"; PsiElement context = InjectedLanguageManager.getInstance(psiFile.getProject()).getInjectionHost(psiFile); if (context != null) { error += "context: " + context + "; text: '" + context.getText() + "'\n"; error += "context file: " + context.getContainingFile() + "\n"; } error += "document window ranges: " + Arrays.asList(((DocumentWindow) document).getHostRanges()) + "\n"; } LOG.error(error); // document.replaceString(0, documentLength, psiFile.getText()); return false; }
/** * @param hideByAnyKey * @param x <code>x</code> coordinate in layered pane coordinate system. * @param y <code>y</code> coordinate in layered pane coordinate system. */ @Nullable public static LightweightHint showEditorFragmentHintAt( Editor editor, TextRange range, int x, int y, boolean showUpward, boolean showFolding, boolean hideByAnyKey) { if (ApplicationManager.getApplication().isUnitTestMode()) return null; Document document = editor.getDocument(); int startOffset = range.getStartOffset(); int startLine = document.getLineNumber(startOffset); CharSequence text = document.getCharsSequence(); // There is a possible case that we have a situation like below: // line 1 // line 2 <fragment start> // line 3<fragment end> // We don't want to include 'line 2' to the target fragment then. boolean incrementLine = false; for (int offset = startOffset, max = Math.min(range.getEndOffset(), text.length()); offset < max; offset++) { char c = text.charAt(offset); incrementLine = StringUtil.isWhiteSpace(c); if (!incrementLine || c == '\n') { break; } } if (incrementLine) { startLine++; } int endLine = Math.min(document.getLineNumber(range.getEndOffset()) + 1, document.getLineCount() - 1); // if (editor.logicalPositionToXY(new LogicalPosition(startLine, 0)).y >= // editor.logicalPositionToXY(new LogicalPosition(endLine, 0)).y) return null; if (startLine >= endLine) return null; EditorFragmentComponent fragmentComponent = createEditorFragmentComponent(editor, startLine, endLine, showFolding, true); if (showUpward) { y -= fragmentComponent.getPreferredSize().height + 10; y = Math.max(0, y); } final JComponent c = editor.getComponent(); x = SwingUtilities.convertPoint(c, new Point(-3, 0), UIUtil.getRootPane(c)).x; // IDEA-68016 Point p = new Point(x, y); LightweightHint hint = new MyComponentHint(fragmentComponent); HintManagerImpl.getInstanceImpl() .showEditorHint( hint, editor, p, (hideByAnyKey ? HintManager.HIDE_BY_ANY_KEY : 0) | HintManager.HIDE_BY_TEXT_CHANGE | HintManager.HIDE_BY_MOUSEOVER, 0, false, new HintHint(editor, p)); return hint; }