@Override protected Transferable createTransferable(JComponent c) { JTextPane aTextPane = (JTextPane) c; HTMLEditorKit kit = ((HTMLEditorKit) aTextPane.getEditorKit()); StyledDocument sdoc = aTextPane.getStyledDocument(); int sel_start = aTextPane.getSelectionStart(); int sel_end = aTextPane.getSelectionEnd(); int i = sel_start; StringBuilder output = new StringBuilder(); while (i < sel_end) { Element e = sdoc.getCharacterElement(i); Object nameAttr = e.getAttributes().getAttribute(StyleConstants.NameAttribute); int start = e.getStartOffset(), end = e.getEndOffset(); if (nameAttr == HTML.Tag.BR) { output.append("\n"); } else if (nameAttr == HTML.Tag.CONTENT) { if (start < sel_start) { start = sel_start; } if (end > sel_end) { end = sel_end; } try { String str = sdoc.getText(start, end - start); output.append(str); } catch (BadLocationException ble) { Debug.error(me + "Copy-paste problem!\n%s", ble.getMessage()); } } i = end; } return new StringSelection(output.toString()); }
// TODO: make this a method of SikuliDocument, no need to pass document as argument private void changeIndentation(DefaultStyledDocument doc, int linenum, int columns) throws BadLocationException { PreferencesUser pref = PreferencesUser.getInstance(); boolean expandTab = pref.getExpandTab(); int tabWidth = pref.getTabWidth(); if (linenum < 0) { throw new BadLocationException("Negative line", -1); } Element map = doc.getDefaultRootElement(); if (linenum >= map.getElementCount()) { throw new BadLocationException("No such line", doc.getLength() + 1); } if (columns == 0) { return; } Element lineElem = map.getElement(linenum); int lineStart = lineElem.getStartOffset(); int lineLength = lineElem.getEndOffset() - lineStart; String line = doc.getText(lineStart, lineLength); // determine current indentation and number of whitespace characters int wsChars; int indentation = 0; for (wsChars = 0; wsChars < line.length(); wsChars++) { char c = line.charAt(wsChars); if (c == ' ') { indentation++; } else if (c == '\t') { indentation += tabWidth; } else { break; } } int newIndentation = indentation + columns; if (newIndentation <= 0) { doc.remove(lineStart, wsChars); return; } // build whitespace string for new indentation StringBuilder newWs = new StringBuilder(newIndentation / tabWidth + tabWidth - 1); int ind = 0; if (!expandTab) { for (; ind + tabWidth <= newIndentation; ind += tabWidth) { newWs.append('\t'); } } for (; ind < newIndentation; ind++) { newWs.append(' '); } doc.replace(lineStart, wsChars, newWs.toString(), null); }
/** * Returns the line. * * @param content the content * @param offset the offset to start at * @return the line */ protected String getLine(String content, int offset) { int line = m_RootElement.getElementIndex(offset); Element lineElement = m_RootElement.getElement(line); int start = lineElement.getStartOffset(); int end = lineElement.getEndOffset(); return content.substring(start, end - 1); }
/** * Paints the word-wrapped text. * * @param g The graphics context in which to paint. * @param a The shape (usually a rectangle) in which to paint. */ public void paint(Graphics g, Shape a) { Rectangle alloc = (a instanceof Rectangle) ? (Rectangle) a : a.getBounds(); tabBase = alloc.x; Graphics2D g2d = (Graphics2D) g; host = (RSyntaxTextArea) getContainer(); int ascent = host.getMaxAscent(); int fontHeight = host.getLineHeight(); FoldManager fm = host.getFoldManager(); TokenPainter painter = host.getTokenPainter(); Element root = getElement(); // Whether token styles should always be painted, even in selections int selStart = host.getSelectionStart(); int selEnd = host.getSelectionEnd(); boolean useSelectedTextColor = host.getUseSelectedTextColor(); int n = getViewCount(); // Number of lines. int x = alloc.x + getLeftInset(); tempRect.y = alloc.y + getTopInset(); Rectangle clip = g.getClipBounds(); for (int i = 0; i < n; i++) { tempRect.x = x + getOffset(X_AXIS, i); // tempRect.y = y + getOffset(Y_AXIS, i); tempRect.width = getSpan(X_AXIS, i); tempRect.height = getSpan(Y_AXIS, i); // System.err.println("For line " + i + ": tempRect==" + tempRect); if (tempRect.intersects(clip)) { Element lineElement = root.getElement(i); int startOffset = lineElement.getStartOffset(); int endOffset = lineElement.getEndOffset() - 1; // Why always "-1"? View view = getView(i); if (!useSelectedTextColor || selStart == selEnd || (startOffset >= selEnd || endOffset < selStart)) { drawView(painter, g2d, alloc, view, fontHeight, tempRect.y + ascent); } else { // System.out.println("Drawing line with selection: " + i); drawViewWithSelection( painter, g2d, alloc, view, fontHeight, tempRect.y + ascent, selStart, selEnd); } } tempRect.y += tempRect.height; Fold possibleFold = fm.getFoldForLine(i); if (possibleFold != null && possibleFold.isCollapsed()) { i += possibleFold.getCollapsedLineCount(); // Visible indicator of collapsed lines Color c = RSyntaxUtilities.getFoldedLineBottomColor(host); if (c != null) { g.setColor(c); g.drawLine(x, tempRect.y - 1, alloc.width, tempRect.y - 1); } } } }
/** * Inserting text into the start of a paragraph with different attributes. * * <p>This test is equivalent to <code>doc.insertString(insertOffset, newLine, italic)</code>, * where <code>insertOffset = paragraph.getEndOffset()</code>. */ public void testInsertDiffAttrsParStart() throws Exception { insertOffset = paragraph.getEndOffset(); // doc.insertString(insertOffset, newLine, italic); content.insertString(insertOffset, newLine); event = doc.new DefaultDocumentEvent(insertOffset, newLineLen, EventType.INSERT); ElementSpec[] specs = { new ElementSpec(null, ElementSpec.EndTagType), new ElementSpec(null, ElementSpec.StartTagType), new ElementSpec(italic, ElementSpec.ContentType, newLineLen), new ElementSpec(null, ElementSpec.EndTagType), new ElementSpec(null, ElementSpec.StartTagType) }; specs[4].setDirection(ElementSpec.JoinNextDirection); buf.insert(insertOffset, newLineLen, specs, event); List<?> edits = getEdits(event); assertEquals(3, edits.size()); assertChange(edits.get(0), new int[] {15, 17}, new int[] {15, 16}); assertChange(edits.get(1), new int[] {}, new int[] {16, 17}); assertChange(edits.get(2), new int[] {}, new int[] {16, 17}); assertChildren( root.getElement(0), new int[] {0, 5, 5, 9, 9, 15, 15, 16}, new AttributeSet[] {null, bold, italic, null}); assertChildren(root.getElement(1), new int[] {16, 17}, new AttributeSet[] {italic}); assertChildren(root.getElement(2), new int[] {17, 22}, new AttributeSet[] {null}); assertEquals("\n", getText(doc.getCharacterElement(insertOffset))); assertEquals("text\n", getText(doc.getCharacterElement(insertOffset + newLineLen))); }
/* */ protected void drawLine( int paramInt1, int paramInt2, Graphics paramGraphics, int paramInt3, int paramInt4) /* */ { /* 105 */ Element localElement1 = getElement(); /* 106 */ Element localElement2 = localElement1.getElement(localElement1.getElementIndex(paramInt1)); /* */ try /* */ { /* 110 */ if (localElement2.isLeaf()) { /* 111 */ drawText( localElement2, paramInt1, paramInt2, paramGraphics, paramInt3, paramInt4); /* */ } /* */ else { /* 114 */ int i = localElement2.getElementIndex(paramInt1); /* 115 */ int j = localElement2.getElementIndex(paramInt2); /* 116 */ for (; i <= j; i++) { /* 117 */ Element localElement3 = localElement2.getElement(i); /* 118 */ int k = Math.max(localElement3.getStartOffset(), paramInt1); /* 119 */ int m = Math.min(localElement3.getEndOffset(), paramInt2); /* 120 */ paramInt3 = drawText(localElement3, k, m, paramGraphics, paramInt3, paramInt4); /* */ } /* */ } /* */ } catch (BadLocationException localBadLocationException) { /* 124 */ throw new StateInvariantError("Can't render: " + paramInt1 + "," + paramInt2); /* */ } /* */ }
/** * Writes out text. If a range is specified when the constructor is invoked, then only the * appropriate range of text is written out. * * @param elem an Element * @exception IOException on any I/O error * @exception BadLocationException if pos represents an invalid location within the document. */ protected void text(Element elem) throws BadLocationException, IOException { int start = Math.max(getStartOffset(), elem.getStartOffset()); int end = Math.min(getEndOffset(), elem.getEndOffset()); if (start < end) { if (segment == null) { segment = new Segment(); } getDocument().getText(start, end - start, segment); newlineOutputed = false; if (segment.count > 0) { if (segment.array[segment.offset + segment.count - 1] == '\n') { newlineOutputed = true; } if (inPre && end == preEndOffset) { if (segment.count > 1) { segment.count--; } else { return; } } replaceEntities = true; setCanWrapLines(!inPre); write(segment.array, segment.offset, segment.count); setCanWrapLines(false); replaceEntities = false; } } }
public int computeDocumentOffset(int line, int column) throws BadLocationException { if (line < 0 || column < 0) throw new BadLocationException("Negative line/col", -1); Element lineElement = editor.getDocument().getDefaultRootElement().getElement(line - 1); int beginLineOffset = lineElement.getStartOffset(); int endLineOffset = lineElement.getEndOffset(); String text = editor.getDocument().getText(beginLineOffset, endLineOffset - beginLineOffset); int parserChar = 1; int documentChar = 0; while (parserChar < column) { if (documentChar < text.length() && text.charAt(documentChar) == '\t') { parserChar += 8; documentChar += 1; } else { parserChar += 1; documentChar += 1; } } return beginLineOffset + documentChar; }
/** * Create a new AbstractWriter with the indicated Writer and Element. The full range of the * Element will be used. */ protected AbstractWriter(Writer writer, Element elt) { this.writer = writer; this.iter = new ElementIterator(elt); this.document = elt.getDocument(); this.startOffset = elt.getStartOffset(); this.endOffset = elt.getEndOffset(); }
/** * Output the text of the indicated Element, properly clipping it to the range of the Document * specified when the AbstractWriter was created. */ protected void text(Element elt) throws BadLocationException, IOException { int eltStart = elt.getStartOffset(); int eltEnd = elt.getEndOffset(); eltStart = Math.max(eltStart, startOffset); eltEnd = Math.min(eltEnd, endOffset); write(document.getText(eltStart, eltEnd)); }
/** * Provides a mapping from the view coordinate space to the logical coordinate space of the model. * * @param fx the X coordinate >= 0 * @param fy the Y coordinate >= 0 * @param a the allocated region to render into * @return the location within the model that best represents the given point in the view >= 0 */ @Override public int viewToModel(float fx, float fy, Shape a, Position.Bias[] bias) { bias[0] = Position.Bias.Forward; Rectangle alloc = a.getBounds(); RSyntaxDocument doc = (RSyntaxDocument) getDocument(); int x = (int) fx; int y = (int) fy; // If they're asking about a view position above the area covered by // this view, then the position is assumed to be the starting position // of this view. if (y < alloc.y) { return getStartOffset(); } // If they're asking about a position below this view, the position // is assumed to be the ending position of this view. else if (y > alloc.y + alloc.height) { return host.getLastVisibleOffset(); } // They're asking about a position within the coverage of this view // vertically. So, we figure out which line the point corresponds to. // If the line is greater than the number of lines contained, then // simply use the last line as it represents the last possible place // we can position to. else { Element map = doc.getDefaultRootElement(); int lineIndex = Math.abs((y - alloc.y) / lineHeight); // metrics.getHeight() ); FoldManager fm = host.getFoldManager(); // System.out.print("--- " + lineIndex); lineIndex += fm.getHiddenLineCountAbove(lineIndex, true); // System.out.println(" => " + lineIndex); if (lineIndex >= map.getElementCount()) { return host.getLastVisibleOffset(); } Element line = map.getElement(lineIndex); // If the point is to the left of the line... if (x < alloc.x) { return line.getStartOffset(); } else if (x > alloc.x + alloc.width) { return line.getEndOffset() - 1; } else { // Determine the offset into the text int p0 = line.getStartOffset(); Token tokenList = doc.getTokenListForLine(lineIndex); tabBase = alloc.x; int offs = tokenList.getListOffset((RSyntaxTextArea) getContainer(), this, tabBase, x); return offs != -1 ? offs : p0; } } // End of else. }
/** Returns the offset where the selection ends on the specified line. */ public int getSelectionEnd(int line) { if (line == selectionEndLine) return selectionEnd; else if (rectSelect) { Element map = document.getDefaultRootElement(); int end = selectionEnd - map.getElement(selectionEndLine).getStartOffset(); Element lineElement = map.getElement(line); int lineStart = lineElement.getStartOffset(); int lineEnd = lineElement.getEndOffset() - 1; return Math.min(lineEnd, lineStart + end); } else return getLineEndOffset(line) - 1; }
public File reparseBefore() { Element e = this.getDocument().getDefaultRootElement(); if (e.getEndOffset() - e.getStartOffset() == 1) { return null; } File temp = FileManager.createTempFile("reparse"); try { writeFile(temp.getAbsolutePath()); return temp; } catch (IOException ex) { } return null; }
private void handleDecreaseIndent(int line, Element elem, StyledDocument doc) throws BadLocationException { int start = elem.getStartOffset(); int end = elem.getEndOffset() - 1; doc.getText(start, end - start, segLine); int i = segLine.offset; end = i + segLine.count; if (end > i) { String leadingWS = PythonIndentation.getLeadingWhitespace(doc, start, end - start); int toRemove = indentationLogic.checkDedent(leadingWS, line + 1); doc.remove(start, toRemove); } }
// <editor-fold defaultstate="collapsed" desc="replace text patterns with image buttons"> public boolean reparse() { File temp = null; Element e = this.getDocument().getDefaultRootElement(); if (e.getEndOffset() - e.getStartOffset() == 1) { return true; } if ((temp = reparseBefore()) != null) { if (reparseAfter(temp)) { updateDocumentListeners(); return true; } } return false; }
/** * Returns a token list for the specified segment of text representing the specified line number. * This method is basically a wrapper for <code>tokenMaker.getTokenList</code> that takes into * account the last token on the previous line to assure token accuracy. * * @param line The line number of <code>text</code> in the document, >= 0. * @return A token list representing the specified line. */ public final Token getTokenListForLine(int line) { Element map = getDefaultRootElement(); Element elem = map.getElement(line); int startOffset = elem.getStartOffset(); // int endOffset = (line==map.getElementCount()-1 ? elem.getEndOffset() - 1: // elem.getEndOffset() - 1); int endOffset = elem.getEndOffset() - 1; // Why always "-1"? try { getText(startOffset, endOffset - startOffset, s); } catch (BadLocationException ble) { ble.printStackTrace(); return null; } int initialTokenType = line == 0 ? Token.NULL : getLastTokenTypeOnLine(line - 1); return tokenMaker.getTokenList(s, initialTokenType, startOffset); }
private void checkCompletion(java.awt.event.KeyEvent ke) throws BadLocationException { Document doc = getDocument(); Element root = doc.getDefaultRootElement(); int pos = getCaretPosition(); int lineIdx = root.getElementIndex(pos); Element line = root.getElement(lineIdx); int start = line.getStartOffset(), len = line.getEndOffset() - start; String strLine = doc.getText(start, len - 1); Debug.log(9, "[" + strLine + "]"); if (strLine.endsWith("find") && ke.getKeyChar() == '(') { ke.consume(); doc.insertString(pos, "(", null); ButtonCapture btnCapture = new ButtonCapture(this, line); insertComponent(btnCapture); doc.insertString(pos + 2, ")", null); } }
/** * Makes our private <code>Segment s</code> point to the text in our document referenced by the * specified element. Note that <code>line</code> MUST be a valid line number in the document. * * @param line The line number you want to get. */ private final void setSharedSegment(int line) { Element map = getDefaultRootElement(); // int numLines = map.getElementCount(); Element element = map.getElement(line); if (element == null) throw new InternalError("Invalid line number: " + line); int startOffset = element.getStartOffset(); // int endOffset = (line==numLines-1 ? // element.getEndOffset()-1 : element.getEndOffset() - 1); int endOffset = element.getEndOffset() - 1; // Why always "-1"? try { getText(startOffset, endOffset - startOffset, s); } catch (BadLocationException ble) { throw new InternalError("Text range not in document: " + startOffset + "-" + endOffset); } }
private void parse(Element node) { if (!showThumbs) { // do not show any thumbnails return; } int count = node.getElementCount(); for (int i = 0; i < count; i++) { Element elm = node.getElement(i); Debug.log(8, elm.toString()); if (elm.isLeaf()) { int start = elm.getStartOffset(), end = elm.getEndOffset(); parseRange(start, end); } else { parse(elm); } } }
void editorPane_keyPressed(KeyEvent e) { StyledDocument doc = editorPane.getStyledDocument(); int pos = editorPane.getCaretPosition(); int code = e.getKeyCode(); Element el; switch (code) { case KeyEvent.VK_BACK_SPACE: case KeyEvent.VK_DELETE: case KeyEvent.VK_LEFT: case KeyEvent.VK_KP_LEFT: if (pos == 0) return; // we want to get the element to the left of position. el = doc.getCharacterElement(pos - 1); break; case KeyEvent.VK_RIGHT: case KeyEvent.VK_KP_RIGHT: // we want to get the element to the right of position. el = doc.getCharacterElement(pos + 1); break; default: return; // bail we don't handle it. } AttributeSet attr = el.getAttributes(); String el_name = (String) attr.getAttribute(StyleConstants.NameAttribute); int el_range = el.getEndOffset() - el.getStartOffset() - 1; if (el_name.startsWith("Parameter") && StyleConstants.getComponent(attr) != null) { try { switch (code) { case KeyEvent.VK_BACK_SPACE: case KeyEvent.VK_DELETE: doc.remove(el.getStartOffset(), el_range); break; case KeyEvent.VK_LEFT: case KeyEvent.VK_KP_LEFT: editorPane.setCaretPosition(pos - el_range); break; case KeyEvent.VK_RIGHT: case KeyEvent.VK_KP_RIGHT: editorPane.setCaretPosition(pos + (el_range)); break; } } catch (BadLocationException ex) { } } }
/** Returns the selected text, or null if no selection is active. */ public final String getSelectedText() { if (selectionStart == selectionEnd) return null; if (rectSelect) { // Return each row of the selection on a new line Element map = document.getDefaultRootElement(); int start = selectionStart - map.getElement(selectionStartLine).getStartOffset(); int end = selectionEnd - map.getElement(selectionEndLine).getStartOffset(); // Certain rectangles satisfy this condition... if (end < start) { int tmp = end; end = start; start = tmp; } StringBuffer buf = new StringBuffer(); Segment seg = new Segment(); for (int i = selectionStartLine; i <= selectionEndLine; i++) { Element lineElement = map.getElement(i); int lineStart = lineElement.getStartOffset(); int lineEnd = lineElement.getEndOffset() - 1; int lineLen = lineEnd - lineStart; lineStart = Math.min(lineStart + start, lineEnd); lineLen = Math.min(end - start, lineEnd - lineStart); getText(lineStart, lineLen, seg); buf.append(seg.array, seg.offset, seg.count); if (i != selectionEndLine) buf.append('\n'); } return buf.toString(); } else { return getText(selectionStart, selectionEnd - selectionStart); } }
private int getFunctionStartOffset(String func, Element node) throws BadLocationException { Document doc = getDocument(); int count = node.getElementCount(); Pattern patDef = Pattern.compile("def\\s+" + func + "\\s*\\("); for (int i = 0; i < count; i++) { Element elm = node.getElement(i); if (elm.isLeaf()) { int start = elm.getStartOffset(), end = elm.getEndOffset(); String line = doc.getText(start, end - start); Matcher matcher = patDef.matcher(line); if (matcher.find()) { return start; } } else { int p = getFunctionStartOffset(func, elm); if (p >= 0) { return p; } } } return -1; }
public void write(Writer out, Document doc, int pos, int len, Map<String, String> copiedImgs) throws IOException, BadLocationException { Debug.log(9, "SikuliEditorKit.write %d %d", pos, len); DefaultStyledDocument sdoc = (DefaultStyledDocument) doc; int i = pos; String absPath; while (i < pos + len) { Element e = sdoc.getCharacterElement(i); int start = e.getStartOffset(), end = e.getEndOffset(); if (e.getName().equals(StyleConstants.ComponentElementName)) { // A image argument to be filled AttributeSet attr = e.getAttributes(); Component com = StyleConstants.getComponent(attr); out.write(com.toString()); if (copiedImgs != null && (com instanceof EditorPatternButton || com instanceof EditorPatternLabel)) { if (com instanceof EditorPatternButton) { absPath = ((EditorPatternButton) com).getFilename(); } else { absPath = ((EditorPatternLabel) com).getFile(); } String fname = (new File(absPath)).getName(); copiedImgs.put(fname, absPath); Debug.log(3, "save image for copy&paste: " + fname + " -> " + absPath); } } else { if (start < pos) { start = pos; } if (end > pos + len) { end = pos + len; } out.write(doc.getText(start, end - start)); } i = end; } out.close(); }
private String getText(final Element element) throws BadLocationException { return getText(element.getStartOffset(), element.getEndOffset() - element.getStartOffset()); }
/** Return true if the Element's range overlaps our desired output range; false otherwise. */ protected boolean inRange(Element elt) { int eltStart = elt.getStartOffset(); int eltEnd = elt.getEndOffset(); return ((eltStart >= startOffset && eltStart < endOffset) || (eltEnd >= startOffset && eltEnd < endOffset)); }
/** * Return the text of the Document that is associated with the given Element. If the Element is * not a leaf Element, this will throw BadLocationException. * * @throws BadLocationException if the element is not a leaf */ protected String getText(Element elt) throws BadLocationException { if (!elt.isLeaf()) throw new BadLocationException("Element is not a leaf", elt.getStartOffset()); return document.getText(elt.getStartOffset(), elt.getEndOffset()); }
/** * Replaces the selection with the specified text. * * @param selectedText The replacement text for the selection */ public void setSelectedText(String selectedText) { if (!editable) { throw new InternalError("Text component" + " read only"); } document.beginCompoundEdit(); try { if (rectSelect) { Element map = document.getDefaultRootElement(); int start = selectionStart - map.getElement(selectionStartLine).getStartOffset(); int end = selectionEnd - map.getElement(selectionEndLine).getStartOffset(); // Certain rectangles satisfy this condition... if (end < start) { int tmp = end; end = start; start = tmp; } int lastNewline = 0; int currNewline = 0; for (int i = selectionStartLine; i <= selectionEndLine; i++) { Element lineElement = map.getElement(i); int lineStart = lineElement.getStartOffset(); int lineEnd = lineElement.getEndOffset() - 1; int rectStart = Math.min(lineEnd, lineStart + start); document.remove(rectStart, Math.min(lineEnd - rectStart, end - start)); if (selectedText == null) continue; currNewline = selectedText.indexOf('\n', lastNewline); if (currNewline == -1) currNewline = selectedText.length(); document.insertString(rectStart, selectedText.substring(lastNewline, currNewline), null); lastNewline = Math.min(selectedText.length(), currNewline + 1); } if (selectedText != null && currNewline != selectedText.length()) { int offset = map.getElement(selectionEndLine).getEndOffset() - 1; document.insertString(offset, "\n", null); document.insertString(offset + 1, selectedText.substring(currNewline + 1), null); } } else { document.remove(selectionStart, selectionEnd - selectionStart); if (selectedText != null) { document.insertString(selectionStart, selectedText, null); } } } catch (BadLocationException bl) { bl.printStackTrace(); throw new InternalError("Cannot replace" + " selection"); } // No matter what happends... stops us from leaving document // in a bad state finally { document.endCompoundEdit(); } setCaretPosition(selectionEnd); }
/** * Returns the length of the specified line. * * @param line The line */ public int getLineLength(int line) { Element lineElement = document.getDefaultRootElement().getElement(line); if (lineElement == null) return -1; else return lineElement.getEndOffset() - lineElement.getStartOffset() - 1; }
private void insertNewlineWithAutoIndent(JTextComponent text) { try { int caretPos = text.getCaretPosition(); StyledDocument doc = (StyledDocument) text.getDocument(); Element map = doc.getDefaultRootElement(); int lineNum = map.getElementIndex(caretPos); Element line = map.getElement(lineNum); int start = line.getStartOffset(); int end = line.getEndOffset() - 1; int len = end - start; String s = doc.getText(start, len); String leadingWS = PythonIndentation.getLeadingWhitespace(doc, start, caretPos - start); StringBuffer sb = new StringBuffer("\n"); sb.append(leadingWS); // TODO better control over automatic indentation indentationLogic.checkIndent(leadingWS, lineNum + 1); // If there is only whitespace between the caret and // the EOL, pressing Enter auto-indents the new line to // the same place as the previous line. int nonWhitespacePos = PythonIndentation.atEndOfLine(doc, caretPos, start, s, len); if (nonWhitespacePos == -1) { if (leadingWS.length() == len) { // If the line was nothing but whitespace, select it // so its contents get removed. text.setSelectionStart(start); } else { // Select the whitespace between the caret and the EOL // to remove it text.setSelectionStart(caretPos); } text.setSelectionEnd(end); text.replaceSelection(sb.toString()); // auto-indentation for python statements like if, while, for, try, // except, def, class and auto-deindentation for break, continue, // pass, return analyseDocument(doc, lineNum, indentationLogic); // auto-completion: add colon if it is obvious if (indentationLogic.shouldAddColon()) { doc.insertString(caretPos, ":", null); indentationLogic.setLastLineEndsWithColon(); } int lastLineChange = indentationLogic.shouldChangeLastLineIndentation(); int nextLineChange = indentationLogic.shouldChangeNextLineIndentation(); if (lastLineChange != 0) { Debug.log(5, "change line %d indentation by %d columns", lineNum + 1, lastLineChange); changeIndentation((DefaultStyledDocument) doc, lineNum, lastLineChange); // nextLineChange was determined based on indentation of last line before // the change nextLineChange += lastLineChange; } if (nextLineChange != 0) { Debug.log(5, "change line %d indentation by %d columns", lineNum + 2, nextLineChange); changeIndentation((DefaultStyledDocument) doc, lineNum + 1, nextLineChange); } } // If there is non-whitespace between the caret and the // EOL, pressing Enter takes that text to the next line // and auto-indents it to the same place as the last // line. Additional auto-indentation or dedentation for // specific python statements is only done for the next line. else { text.setCaretPosition(nonWhitespacePos); doc.insertString(nonWhitespacePos, sb.toString(), null); analyseDocument(doc, lineNum, indentationLogic); int nextLineChange = indentationLogic.shouldChangeNextLineIndentation(); if (nextLineChange != 0) { Debug.log(5, "change line %d indentation by %d columns", lineNum + 2, nextLineChange); changeIndentation((DefaultStyledDocument) doc, lineNum + 1, nextLineChange); } } } catch (BadLocationException ble) { text.replaceSelection("\n"); Debug.error(me + "Problem while inserting new line with auto-indent\n%s", ble.getMessage()); } }
/** * Actually paints the text area. Only lines that have been damaged are repainted. * * @param g The graphics context with which to paint. * @param a The allocated region in which to render. */ @Override public void paint(Graphics g, Shape a) { RSyntaxDocument document = (RSyntaxDocument) getDocument(); Rectangle alloc = a.getBounds(); tabBase = alloc.x; host = (RSyntaxTextArea) getContainer(); Rectangle clip = g.getClipBounds(); // An attempt to speed things up for files with long lines. Note that // this will actually slow things down a bit for the common case of // regular-length lines, but it doesn't make a perceivable difference. clipStart = clip.x; clipEnd = clipStart + clip.width; lineHeight = host.getLineHeight(); ascent = host.getMaxAscent(); // metrics.getAscent(); int heightAbove = clip.y - alloc.y; int linesAbove = Math.max(0, heightAbove / lineHeight); FoldManager fm = host.getFoldManager(); linesAbove += fm.getHiddenLineCountAbove(linesAbove, true); Rectangle lineArea = lineToRect(a, linesAbove); int y = lineArea.y + ascent; int x = lineArea.x; Element map = getElement(); int lineCount = map.getElementCount(); // Whether token styles should always be painted, even in selections int selStart = host.getSelectionStart(); int selEnd = host.getSelectionEnd(); RSyntaxTextAreaHighlighter h = (RSyntaxTextAreaHighlighter) host.getHighlighter(); Graphics2D g2d = (Graphics2D) g; Token token; // System.err.println("Painting lines: " + linesAbove + " to " + (endLine-1)); TokenPainter painter = host.getTokenPainter(); int line = linesAbove; // int count = 0; while (y < clip.y + clip.height + ascent && line < lineCount) { Fold fold = fm.getFoldForLine(line); Element lineElement = map.getElement(line); int startOffset = lineElement.getStartOffset(); // int endOffset = (line==lineCount ? lineElement.getEndOffset()-1 : // lineElement.getEndOffset()-1); int endOffset = lineElement.getEndOffset() - 1; // Why always "-1"? h.paintLayeredHighlights(g2d, startOffset, endOffset, a, host, this); // Paint a line of text. token = document.getTokenListForLine(line); if (selStart == selEnd || startOffset >= selEnd || endOffset < selStart) { drawLine(painter, token, g2d, x, y, line); } else { // System.out.println("Drawing line with selection: " + line); drawLineWithSelection(painter, token, g2d, x, y, selStart, selEnd); } if (fold != null && fold.isCollapsed()) { // Visible indicator of collapsed lines Color c = RSyntaxUtilities.getFoldedLineBottomColor(host); if (c != null) { g.setColor(c); g.drawLine(x, y + lineHeight - ascent - 1, host.getWidth(), y + lineHeight - ascent - 1); } // Skip to next line to paint, taking extra care for lines with // block ends and begins together, e.g. "} else {" do { int hiddenLineCount = fold.getLineCount(); if (hiddenLineCount == 0) { // Fold parser identified a zero-line fold region. // This is really a bug, but we'll be graceful here // and avoid an infinite loop. break; } line += hiddenLineCount; fold = fm.getFoldForLine(line); } while (fold != null && fold.isCollapsed()); } y += lineHeight; line++; // count++; } // System.out.println("SyntaxView: lines painted=" + count); }