/** * Shifts the line range specified by <code>lines</code> in <code>document</code>. The amount that * the lines get shifted are determined by the first line in the range, all subsequent lines are * adjusted accordingly. The passed Java project may be <code>null</code>, it is used solely to * obtain formatter preferences. * * @param document the document to be changed * @param lines the line range to be shifted * @param project the Java project to get the formatter preferences from, or <code>null</code> if * global preferences should be used * @param result the result from a previous call to <code>shiftLines</code>, in order to maintain * comment line properties, or <code>null</code>. Note that the passed result may be changed * by the call. * @return an indent result that may be queried for changes and can be reused in subsequent * indentation operations * @throws BadLocationException if <code>lines</code> is not a valid line range on <code>document * </code> */ public static IndentResult shiftLines( IDocument document, ILineRange lines, IJavaProject project, IndentResult result) throws BadLocationException { int numberOfLines = lines.getNumberOfLines(); if (numberOfLines < 1) return new IndentResult(null); result = reuseOrCreateToken(result, numberOfLines); result.hasChanged = false; JavaHeuristicScanner scanner = new JavaHeuristicScanner(document); JavaIndenter indenter = new JavaIndenter(document, scanner, project); String current = getCurrentIndent(document, lines.getStartLine()); StringBuffer correct = indenter.computeIndentation(document.getLineOffset(lines.getStartLine())); if (correct == null) return result; // bail out int tabSize = CodeFormatterUtil.getTabWidth(project); StringBuffer addition = new StringBuffer(); int difference = subtractIndent(correct, current, addition, tabSize); if (difference == 0) return result; if (result.leftmostLine == -1) result.leftmostLine = getLeftMostLine(document, lines, tabSize); int maxReduction = computeVisualLength( getCurrentIndent(document, result.leftmostLine + lines.getStartLine()), tabSize); if (difference > 0) { for (int line = lines.getStartLine(), last = line + numberOfLines, i = 0; line < last; line++) addIndent(document, line, addition, result.commentLinesAtColumnZero, i++); } else { int reduction = Math.min(-difference, maxReduction); for (int line = lines.getStartLine(), last = line + numberOfLines, i = 0; line < last; line++) cutIndent(document, line, reduction, tabSize, result.commentLinesAtColumnZero, i++); } result.hasChanged = true; return result; }
/** * Indents a single line using the java heuristic scanner. Javadoc and multi line comments are * indented as specified by the <code>JavaDocAutoIndentStrategy</code>. * * @param document the document * @param line the line to be indented * @param indenter the java indenter * @param scanner the heuristic scanner * @param commentLines the indent token comment booleans * @param lineIndex the zero-based line index * @return <code>true</code> if the document was modified, <code>false</code> if not * @throws BadLocationException if the document got changed concurrently */ private static boolean indentLine( IDocument document, int line, JavaIndenter indenter, JavaHeuristicScanner scanner, boolean[] commentLines, int lineIndex, int tabSize) throws BadLocationException { IRegion currentLine = document.getLineInformation(line); final int offset = currentLine.getOffset(); int wsStart = offset; // where we start searching for non-WS; after the "//" in single line comments String indent = null; if (offset < document.getLength()) { ITypedRegion partition = TextUtilities.getPartition(document, IJavaPartitions.JAVA_PARTITIONING, offset, true); ITypedRegion startingPartition = TextUtilities.getPartition(document, IJavaPartitions.JAVA_PARTITIONING, offset, false); String type = partition.getType(); if (type.equals(IJavaPartitions.JAVA_DOC) || type.equals(IJavaPartitions.JAVA_MULTI_LINE_COMMENT)) { indent = computeJavadocIndent(document, line, scanner, startingPartition); } else if (!commentLines[lineIndex] && startingPartition.getOffset() == offset && startingPartition.getType().equals(IJavaPartitions.JAVA_SINGLE_LINE_COMMENT)) { return false; } } // standard java indentation if (indent == null) { StringBuffer computed = indenter.computeIndentation(offset); if (computed != null) indent = computed.toString(); else indent = new String(); } // change document: // get current white space int lineLength = currentLine.getLength(); int end = scanner.findNonWhitespaceForwardInAnyPartition(wsStart, offset + lineLength); if (end == JavaHeuristicScanner.NOT_FOUND) end = offset + lineLength; int length = end - offset; String currentIndent = document.get(offset, length); // memorize the fact that a line is a single line comment (but not at column 0) and should be // treated like code // as opposed to commented out code, which should keep its slashes at column 0 if (length > 0) { ITypedRegion partition = TextUtilities.getPartition(document, IJavaPartitions.JAVA_PARTITIONING, end, false); if (partition.getOffset() == end && IJavaPartitions.JAVA_SINGLE_LINE_COMMENT.equals(partition.getType())) { commentLines[lineIndex] = true; } } // only change the document if it is a real change if (!indent.equals(currentIndent)) { document.replace(offset, length, indent); return true; } return false; }