/** * Computes and returns the indentation for a javadoc line. The line must be inside a javadoc * comment. * * @param document the document * @param line the line in document * @param scanner the scanner * @param partition the comment partition * @return the indent, or <code>null</code> if not computable * @throws BadLocationException */ private static String computeJavadocIndent( IDocument document, int line, JavaHeuristicScanner scanner, ITypedRegion partition) throws BadLocationException { if (line == 0) // impossible - the first line is never inside a javadoc comment return null; // don't make any assumptions if the line does not start with \s*\* - it might be // commented out code, for which we don't want to change the indent final IRegion lineInfo = document.getLineInformation(line); final int lineStart = lineInfo.getOffset(); final int lineLength = lineInfo.getLength(); final int lineEnd = lineStart + lineLength; int nonWS = scanner.findNonWhitespaceForwardInAnyPartition(lineStart, lineEnd); if (nonWS == JavaHeuristicScanner.NOT_FOUND || document.getChar(nonWS) != '*') { if (nonWS == JavaHeuristicScanner.NOT_FOUND) return document.get(lineStart, lineLength); return document.get(lineStart, nonWS - lineStart); } // take the indent from the previous line and reuse IRegion previousLine = document.getLineInformation(line - 1); int previousLineStart = previousLine.getOffset(); int previousLineLength = previousLine.getLength(); int previousLineEnd = previousLineStart + previousLineLength; StringBuffer buf = new StringBuffer(); int previousLineNonWS = scanner.findNonWhitespaceForwardInAnyPartition(previousLineStart, previousLineEnd); if (previousLineNonWS == JavaHeuristicScanner.NOT_FOUND || document.getChar(previousLineNonWS) != '*') { // align with the comment start if the previous line is not an asterix line previousLine = document.getLineInformationOfOffset(partition.getOffset()); previousLineStart = previousLine.getOffset(); previousLineLength = previousLine.getLength(); previousLineEnd = previousLineStart + previousLineLength; previousLineNonWS = scanner.findNonWhitespaceForwardInAnyPartition(previousLineStart, previousLineEnd); if (previousLineNonWS == JavaHeuristicScanner.NOT_FOUND) previousLineNonWS = previousLineEnd; // add the initial space // TODO this may be controlled by a formatter preference in the future buf.append(' '); } String indentation = document.get(previousLineStart, previousLineNonWS - previousLineStart); buf.insert(0, indentation); return buf.toString(); }
/** * 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; }