From b1a7c95e56bde98a4af96c9575fb97abbbaf1a17 Mon Sep 17 00:00:00 2001 From: Anton Leherbauer Date: Fri, 13 Jul 2007 11:33:50 +0000 Subject: [PATCH] Follow-up fix for 185712: Invalid indenting of code template --- .../corext/template/c/CFormatter.java | 71 ++++++++++++++++--- .../cdt/internal/ui/editor/IndentUtil.java | 29 ++++++-- 2 files changed, 86 insertions(+), 14 deletions(-) diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/template/c/CFormatter.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/template/c/CFormatter.java index 73c68fc3296..b18cc4b595b 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/template/c/CFormatter.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/template/c/CFormatter.java @@ -31,6 +31,7 @@ import org.eclipse.jface.text.TypedPosition; import org.eclipse.jface.text.rules.FastPartitioner; import org.eclipse.jface.text.source.LineRange; import org.eclipse.jface.text.templates.DocumentTemplateContext; +import org.eclipse.jface.text.templates.GlobalTemplateVariables; import org.eclipse.jface.text.templates.TemplateBuffer; import org.eclipse.jface.text.templates.TemplateContext; import org.eclipse.jface.text.templates.TemplateVariable; @@ -95,7 +96,7 @@ public class CFormatter { VariableTracker tracker= new VariableTracker(buffer); IDocument document= tracker.getDocument(); - internalFormat(document, context); + internalFormat(document, context, buffer); convertLineDelimiters(document); convertTabs(document); if (isReplacedAreaEmpty(context)) @@ -110,21 +111,21 @@ public class CFormatter { /** * @param document * @param context + * @param buffer * @throws BadLocationException */ - private void internalFormat(IDocument document, TemplateContext context) throws BadLocationException { + private void internalFormat(IDocument document, TemplateContext context, TemplateBuffer buffer) throws BadLocationException { if (fUseCodeFormatter) { // try to format and fall back to indenting try { format(document, (TranslationUnitContext) context); + return; } catch (BadLocationException e) { - indent(document); } catch (MalformedTreeException e) { - indent(document); } - } else { - indent(document); } + // fallback: indent + indent(document, buffer); } private void convertLineDelimiters(IDocument document) throws BadLocationException { @@ -182,11 +183,17 @@ public class CFormatter { } private void trimStart(IDocument document) throws BadLocationException { - int i= 0; - while ((i != document.getLength()) && Character.isWhitespace(document.getChar(i))) + trimAtOffset(0, document); + } + + private String trimAtOffset(int offset, IDocument document) throws BadLocationException { + int i= offset; + while ((i < document.getLength()) && Character.isWhitespace(document.getChar(i))) i++; - document.replace(0, i, ""); //$NON-NLS-1$ + String trim= document.get(offset, i - offset); + document.replace(offset, i - offset, ""); //$NON-NLS-1$ + return trim; } private boolean isReplacedAreaEmpty(TemplateContext context) { @@ -221,12 +228,56 @@ public class CFormatter { edit.apply(doc, TextEdit.UPDATE_REGIONS); } - private void indent(IDocument document) throws BadLocationException, MalformedTreeException { + private void indent(IDocument document, TemplateBuffer buffer) throws BadLocationException, MalformedTreeException { String indent = CodeFormatterUtil.createIndentString(fInitialIndentLevel, fProject); + prefixSelectionLines(document, buffer); int lineCount= document.getNumberOfLines(); IndentUtil.indentLines(document, new LineRange(0, lineCount), indent); } + /** + * Prefix each line of line_selection substitutions with + * the prefix of the first line. + * + * @param document + * @param buffer + */ + private void prefixSelectionLines(IDocument document, TemplateBuffer buffer) { + TemplateVariable[] variables= buffer.getVariables(); + for (int i = 0; i < variables.length; i++) { + if (variables[i].getName().equals(GlobalTemplateVariables.LineSelection.NAME)) { + if (variables[i].getLength() > 0) { + final int tabWidth= CodeFormatterUtil.getTabWidth(fProject); + int delta= 0; + int[] offsets= variables[i].getOffsets(); + for (int j= 0; j < offsets.length; j++) { + final int offset = offsets[j] + delta; + try { + int startLine= document.getLineOfOffset(offset); + int startOffset= document.getLineOffset(startLine); + int endLine= document.getLineOfOffset(offset+variables[i].getLength() - 1); + String prefix= document.get(startOffset, offset - startOffset); + String shift= trimAtOffset(offset, document); + delta -= shift.length(); + if (shift.length() > 0 && startLine < endLine) { + int shiftWidth= IndentUtil.computeVisualLength(shift, tabWidth); + for (int line= startLine + 1; line <= endLine; ++line) { + delta -= IndentUtil.cutIndent(document, line, shiftWidth, tabWidth); + int lineOffset= document.getLineOffset(line); + document.replace(lineOffset, 0, prefix); + delta += prefix.length(); + } + } + } catch (BadLocationException exc) { + break; + } + } + } + break; + } + } + } + /** * Wraps a {@link TemplateBuffer} and tracks the variable offsets while changes to the buffer * occur. Whitespace variables are also tracked. diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/IndentUtil.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/IndentUtil.java index d57404f180a..98c199d4fb0 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/IndentUtil.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/IndentUtil.java @@ -219,6 +219,7 @@ public final class IndentUtil { * @param line the line * @param indent the indentation to insert * @param commentlines + * @param relative * @param indentInsideLineComments option whether to indent inside line comments starting at column 0 * @throws BadLocationException on concurrent document modification */ @@ -239,18 +240,36 @@ public final class IndentUtil { document.replace(insert, 0, indent.toString()); } + /** + * Cuts the visual equivalent of toDelete characters out of the + * indentation of line line in document. + * + * @param document + * @param line + * @param shiftWidth + * @param tabWidth + * @return number of characters deleted + * @throws BadLocationException + */ + public static int cutIndent(IDocument document, int line, int shiftWidth, int tabWidth) throws BadLocationException { + return cutIndent(document, line, shiftWidth, tabWidth, new boolean[1], 0, false); + } + /** * Cuts the visual equivalent of toDelete characters out of the * indentation of line line in document. Leaves - * leading comment signs alone. + * leading comment signs alone if desired. * * @param document the document * @param line the line * @param toDelete the number of space equivalents to delete. + * @param commentLines + * @param relative * @param indentInsideLineComments option whether to indent inside line comments starting at column 0 + * @return number of characters deleted * @throws BadLocationException on concurrent document modification */ - private static void cutIndent(IDocument document, int line, int toDelete, int tabSize, boolean[] commentLines, int relative, boolean indentInsideLineComments) throws BadLocationException { + private static int cutIndent(IDocument document, int line, int toDelete, int tabSize, boolean[] commentLines, int relative, boolean indentInsideLineComments) throws BadLocationException { IRegion region= document.getLineInformation(line); int from= region.getOffset(); int endOffset= region.getOffset() + region.getLength(); @@ -276,7 +295,8 @@ public final class IndentUtil { if (endOffset > to + 1 && document.get(to, 2).equals(SLASHES)) commentLines[relative]= true; - document.replace(from, to - from, null); + document.replace(from, to - from, ""); //$NON-NLS-1$ + return to - from; } /** @@ -322,7 +342,7 @@ public final class IndentUtil { * @param seq the string to measure * @return the visual length of seq */ - private static int computeVisualLength(CharSequence seq, int tablen) { + public static int computeVisualLength(CharSequence seq, int tablen) { int size= 0; for (int i= 0; i < seq.length(); i++) { @@ -597,4 +617,5 @@ public final class IndentUtil { computed= new StringBuffer(previousIndent); return computed.toString(); } + }