// 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); }
/** * Highlight lines to start or end delimiter. * * @param content the content to parse * @param line the line number * @throws BadLocationException if offsets are wrong */ protected void highlightLinesAfter(String content, int line) throws BadLocationException { int offset = m_RootElement.getElement(line).getEndOffset(); // Start/End delimiter not found, nothing to do int startDelimiter = -1; int endDelimiter = -1; if (getMultiLineComment()) { startDelimiter = indexOf(content, getMultiLineCommentStart(), offset); endDelimiter = indexOf(content, getMultiLineCommentEnd(), offset); } if (startDelimiter < 0) startDelimiter = content.length(); if (endDelimiter < 0) endDelimiter = content.length(); int delimiter = Math.min(startDelimiter, endDelimiter); if (delimiter < offset) return; // Start/End delimiter found, reapply highlighting int endLine = m_RootElement.getElementIndex(delimiter); for (int i = line + 1; i < endLine; i++) { Element branch = m_RootElement.getElement(i); Element leaf = m_Self.getCharacterElement(branch.getStartOffset()); AttributeSet as = leaf.getAttributes(); if (as.isEqual(DEFAULT_COMMENT)) applyHighlighting(content, i); } }
/** * Adds the matching block end. * * @param offset the offset * @return the string after adding the matching block end * @throws BadLocationException if the offset is invalid */ protected String addMatchingBlockEnd(int offset) throws BadLocationException { StringBuffer result; StringBuffer whiteSpace = new StringBuffer(); int line = m_RootElement.getElementIndex(offset); int i = m_RootElement.getElement(line).getStartOffset(); while (true) { String temp = m_Self.getText(i, 1); if (temp.equals(" ") || temp.equals("\t")) { whiteSpace.append(temp); i++; } else { break; } } // assemble string result = new StringBuffer(); result.append(m_BlockStart); result.append("\n"); result.append(whiteSpace.toString()); if (m_UseBlanks) result.append(m_Indentation); else result.append("\t"); result.append("\n"); result.append(whiteSpace.toString()); result.append(m_BlockEnd); return result.toString(); }
/** * Searches for a quote token. * * @param content the content to search * @param startOffset the start of the search * @param endOffset the end of the search * @return the new position */ protected int getQuoteToken(String content, int startOffset, int endOffset) { String quoteDelimiter = content.substring(startOffset, startOffset + 1); String escapeString = escapeQuote(quoteDelimiter); int index; int endOfQuote = startOffset; // skip over the escape quotes in this quote index = content.indexOf(escapeString, endOfQuote + 1); while ((index > -1) && (index < endOffset)) { endOfQuote = index + 1; index = content.indexOf(escapeString, endOfQuote); } // now find the matching delimiter index = content.indexOf(quoteDelimiter, endOfQuote + 1); if ((index < 0) || (index > endOffset)) endOfQuote = endOffset; else endOfQuote = index; m_Self.setCharacterAttributes(startOffset, endOfQuote - startOffset + 1, DEFAULT_STRING, false); return endOfQuote + 1; }
/** * Override to apply syntax highlighting after the document has been updated. * * @param offset the offset * @param str the string to insert * @param a the attribute set, can be null * @throws BadLocationException if offset is invalid */ public void insertString(int offset, String str, AttributeSet a) throws BadLocationException { if (m_AddMatchingEndBlocks && (m_BlockStart.length() > 0) && str.equals(m_BlockStart)) str = addMatchingBlockEnd(offset); else if (m_UseBlanks && str.equals("\t")) str = m_Indentation; super.insertString(offset, str, a); processChangedLines(offset, str.length()); }
/** * Initializes the document. * * @param props the properties to obtain the setup from */ public SyntaxDocument(Properties props) { m_Self = this; m_RootElement = m_Self.getDefaultRootElement(); m_Keywords = new HashMap<String, MutableAttributeSet>(); m_FontSize = DEFAULT_FONT_SIZE; m_FontName = DEFAULT_FONT_FAMILY; putProperty(DefaultEditorKit.EndOfLineStringProperty, "\n"); setup(props); }
public void insertString(int offs, String str, AttributeSet a) throws BadLocationException { if ((getLength() + str.length()) <= size) { super.insertString(offs, str, a); } else { System.err.println( "Tried to make field " + (getLength() + str.length()) + " characters long when max length is " + size); Toolkit.getDefaultToolkit().beep(); } }
/** * Parse the line to determine the appropriate highlighting. * * @param content the content to parse * @param line the line number * @throws BadLocationException if offsets are invalid */ protected void applyHighlighting(String content, int line) throws BadLocationException { int startOffset = m_RootElement.getElement(line).getStartOffset(); int endOffset = m_RootElement.getElement(line).getEndOffset() - 1; int lineLength = endOffset - startOffset; int contentLength = content.length(); if (endOffset >= contentLength) endOffset = contentLength - 1; // check for multi line comments // (always set the comment attribute for the entire line) if (getMultiLineComment()) { if (endingMultiLineComment(content, startOffset, endOffset) || isMultiLineComment() || startingMultiLineComment(content, startOffset, endOffset)) { m_Self.setCharacterAttributes( startOffset, endOffset - startOffset + 1, DEFAULT_COMMENT, false); return; } } // set normal attributes for the line m_Self.setCharacterAttributes(startOffset, lineLength, DEFAULT_NORMAL, true); // check for single line comment int index = content.indexOf(getSingleLineCommentStart(), startOffset); if ((index > -1) && (index < endOffset)) { m_Self.setCharacterAttributes(index, endOffset - index + 1, DEFAULT_COMMENT, false); endOffset = index - 1; } // check for tokens checkForTokens(content, startOffset, endOffset); }
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(); }
/** * Determine how many lines have been changed, then apply highlighting to each line. * * @param offset the offset of the changed lines * @param length the length of the change * @throws BadLocationException if offset is invalid */ public void processChangedLines(int offset, int length) throws BadLocationException { String content = m_Self.getText(0, m_Self.getLength()); // The lines affected by the latest document update int startLine = m_RootElement.getElementIndex(offset); int endLine = m_RootElement.getElementIndex(offset + length); // Make sure all comment lines prior to the start line are commented // and determine if the start line is still in a multi line comment if (getMultiLineComment()) setInsideMultiLineComment(commentLinesBefore(content, startLine)); // Do the actual highlighting for (int i = startLine; i <= endLine; i++) { applyHighlighting(content, i); } // Resolve highlighting to the next end multi line delimiter if (isMultiLineComment()) commentLinesAfter(content, endLine); else highlightLinesAfter(content, endLine); }
/** * Searches for a keyword token. * * @param content the content to search in * @param startOffset the position to start the search fromm * @param endOffset the position to end the search * @return the new position */ protected int getOtherToken(String content, int startOffset, int endOffset) { int endOfToken = startOffset + 1; while (endOfToken <= endOffset) { if (isDelimiter(content.substring(endOfToken, endOfToken + 1))) break; endOfToken++; } String token = content.substring(startOffset, endOfToken); // see if this token has a highlighting format associated with it MutableAttributeSet attr = getKeywordFormatting(token); if (attr != null) m_Self.setCharacterAttributes(startOffset, endOfToken - startOffset, attr, false); return endOfToken + 1; }
/** * Highlight comment lines to matching end delimiter. * * @param content the content to parse * @param line the line number */ protected void commentLinesAfter(String content, int line) { int offset = m_RootElement.getElement(line).getEndOffset(); // End of comment not found, nothing to do int endDelimiter = -1; if (getMultiLineComment()) endDelimiter = indexOf(content, getMultiLineCommentEnd(), offset); if (endDelimiter < 0) return; // Matching start/end of comment found, comment the lines int startDelimiter = lastIndexOf(content, getMultiLineCommentStart(), endDelimiter); if (startDelimiter < 0 || startDelimiter <= offset) { m_Self.setCharacterAttributes(offset, endDelimiter - offset + 1, DEFAULT_COMMENT, false); } }
/** * Highlight lines when a multi line comment is still 'open' (ie. matching end delimiter has not * yet been encountered). * * @param content the content to check * @param line the line number * @return true if there are comment lines before */ protected boolean commentLinesBefore(String content, int line) { int offset = m_RootElement.getElement(line).getStartOffset(); // Start of comment not found, nothing to do int startDelimiter = -1; if (getMultiLineComment()) startDelimiter = lastIndexOf(content, getMultiLineCommentStart(), offset - 2); if (startDelimiter < 0) return false; // Matching start/end of comment found, nothing to do int endDelimiter = indexOf(content, getMultiLineCommentEnd(), startDelimiter); if (endDelimiter < offset & endDelimiter != -1) return false; // End of comment not found, highlight the lines m_Self.setCharacterAttributes( startDelimiter, offset - startDelimiter + 1, DEFAULT_COMMENT, false); return true; }
private void highlightArea(int pos, int len, String col) { SimpleAttributeSet attrs = new SimpleAttributeSet(); StyleConstants.setForeground(attrs, getColour(col)); document.setCharacterAttributes(pos, len, attrs, true); }
/** * Applies syntax highlighting after the document has been updated. * * @param offset the offset of the deletion * @param length the length of the deletion * @throws BadLocationException if offsets are invalid */ public void remove(int offset, int length) throws BadLocationException { super.remove(offset, length); processChangedLines(offset, 0); }