diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/CodeFormatterVisitor.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/CodeFormatterVisitor.java index d597698ec95..0bdc326df14 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/CodeFormatterVisitor.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/CodeFormatterVisitor.java @@ -2128,12 +2128,15 @@ public class CodeFormatterVisitor extends CPPASTVisitor { // preprocessor directive is from a different file continue; } + IASTNodeLocation nodeLocation = statement.getFileLocation(); + if (nodeLocation == null) { + continue; + } if (statement instanceof IASTPreprocessorIfStatement) { IASTPreprocessorIfStatement ifStmt = (IASTPreprocessorIfStatement)statement; inactiveCodeStack.push(Boolean.valueOf(inInactiveCode)); if (!ifStmt.taken()) { if (!inInactiveCode) { - IASTNodeLocation nodeLocation = ifStmt.getFileLocation(); inactiveCodeStart = nodeLocation.getNodeOffset() + nodeLocation.getNodeLength(); inInactiveCode = true; } @@ -2143,7 +2146,6 @@ public class CodeFormatterVisitor extends CPPASTVisitor { inactiveCodeStack.push(Boolean.valueOf(inInactiveCode)); if (!ifdefStmt.taken()) { if (!inInactiveCode) { - IASTNodeLocation nodeLocation = ifdefStmt.getFileLocation(); inactiveCodeStart = nodeLocation.getNodeOffset() + nodeLocation.getNodeLength(); inInactiveCode = true; } @@ -2153,7 +2155,6 @@ public class CodeFormatterVisitor extends CPPASTVisitor { inactiveCodeStack.push(Boolean.valueOf(inInactiveCode)); if (!ifndefStmt.taken()) { if (!inInactiveCode) { - IASTNodeLocation nodeLocation = ifndefStmt.getFileLocation(); inactiveCodeStart = nodeLocation.getNodeOffset() + nodeLocation.getNodeLength(); inInactiveCode = true; } @@ -2161,11 +2162,9 @@ public class CodeFormatterVisitor extends CPPASTVisitor { } else if (statement instanceof IASTPreprocessorElseStatement) { IASTPreprocessorElseStatement elseStmt = (IASTPreprocessorElseStatement)statement; if (!elseStmt.taken() && !inInactiveCode) { - IASTNodeLocation nodeLocation = elseStmt.getFileLocation(); inactiveCodeStart = nodeLocation.getNodeOffset() + nodeLocation.getNodeLength(); inInactiveCode = true; } else if (elseStmt.taken() && inInactiveCode) { - IASTNodeLocation nodeLocation = elseStmt.getFileLocation(); int inactiveCodeEnd = nodeLocation.getNodeOffset(); positions.add(new Position(inactiveCodeStart, inactiveCodeEnd - inactiveCodeStart)); inInactiveCode = false; @@ -2173,21 +2172,17 @@ public class CodeFormatterVisitor extends CPPASTVisitor { } else if (statement instanceof IASTPreprocessorElifStatement) { IASTPreprocessorElifStatement elifStmt = (IASTPreprocessorElifStatement)statement; if (!elifStmt.taken() && !inInactiveCode) { - IASTNodeLocation nodeLocation = elifStmt.getFileLocation(); inactiveCodeStart = nodeLocation.getNodeOffset() + nodeLocation.getNodeLength(); inInactiveCode = true; } else if (elifStmt.taken() && inInactiveCode) { - IASTNodeLocation nodeLocation = elifStmt.getFileLocation(); int inactiveCodeEnd = nodeLocation.getNodeOffset(); positions.add(new Position(inactiveCodeStart, inactiveCodeEnd - inactiveCodeStart)); inInactiveCode = false; } } else if (statement instanceof IASTPreprocessorEndifStatement) { - IASTPreprocessorEndifStatement endifStmt = (IASTPreprocessorEndifStatement)statement; try { boolean wasInInactiveCode = ((Boolean)inactiveCodeStack.pop()).booleanValue(); if (inInactiveCode && !wasInInactiveCode) { - IASTNodeLocation nodeLocation = endifStmt.getFileLocation(); int inactiveCodeEnd = nodeLocation.getNodeOffset(); positions.add(new Position(inactiveCodeStart, inactiveCodeEnd - inactiveCodeStart)); } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/InactiveCodeHighlighting.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/InactiveCodeHighlighting.java index 520750da3a7..42ab7f90fd9 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/InactiveCodeHighlighting.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/InactiveCodeHighlighting.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006 Wind River Systems, Inc. and others. + * Copyright (c) 2006, 2007 Wind River Systems, Inc. and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -22,7 +22,10 @@ import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextInputListener; import org.eclipse.jface.text.TypedPosition; import org.eclipse.swt.widgets.Display; @@ -52,7 +55,7 @@ import org.eclipse.cdt.internal.ui.text.ICReconcilingListener; * @see LineBackgroundPainter * @since 4.0 */ -public class InactiveCodeHighlighting implements ICReconcilingListener { +public class InactiveCodeHighlighting implements ICReconcilingListener, ITextInputListener { /** * Implementation of IRegion that can be reused @@ -82,6 +85,7 @@ public class InactiveCodeHighlighting implements ICReconcilingListener { private CEditor fEditor; /** The list of currently highlighted positions */ private List fInactiveCodePositions= Collections.EMPTY_LIST; + private IDocument fDocument; /** * Create a highlighter for the given key. @@ -134,13 +138,15 @@ public class InactiveCodeHighlighting implements ICReconcilingListener { assert editor != null && lineBackgroundPainter != null; fEditor= editor; fLineBackgroundPainter= lineBackgroundPainter; - fEditor.addReconcileListener(this); ICElement cElement= fEditor.getInputCElement(); if (cElement instanceof ITranslationUnit) { fTranslationUnit = (ITranslationUnit)cElement; } else { fTranslationUnit = null; } + fDocument= fEditor.getDocumentProvider().getDocument(fEditor.getEditorInput()); + fEditor.getViewer().addTextInputListener(this); + fEditor.addReconcileListener(this); } /** @@ -159,8 +165,12 @@ public class InactiveCodeHighlighting implements ICReconcilingListener { } if (fEditor != null) { fEditor.removeReconcileListener(this); + if (fEditor.getViewer() != null) { + fEditor.getViewer().removeTextInputListener(this); + } fEditor= null; fTranslationUnit= null; + fDocument= null; } } @@ -232,13 +242,17 @@ public class InactiveCodeHighlighting implements ICReconcilingListener { // preprocessor directive is from a different file continue; } + IASTNodeLocation[] nodeLocations = statement.getNodeLocations(); + if (nodeLocations.length != 1) { + continue; + } + IASTNodeLocation stmtLocation= nodeLocations[0]; if (statement instanceof IASTPreprocessorIfStatement) { IASTPreprocessorIfStatement ifStmt = (IASTPreprocessorIfStatement)statement; inactiveCodeStack.push(Boolean.valueOf(inInactiveCode)); if (!ifStmt.taken()) { if (!inInactiveCode) { - IASTNodeLocation nodeLocation = ifStmt.getNodeLocations()[0]; - inactiveCodeStart = nodeLocation.getNodeOffset(); + inactiveCodeStart = stmtLocation.getNodeOffset(); inInactiveCode = true; } } @@ -247,8 +261,7 @@ public class InactiveCodeHighlighting implements ICReconcilingListener { inactiveCodeStack.push(Boolean.valueOf(inInactiveCode)); if (!ifdefStmt.taken()) { if (!inInactiveCode) { - IASTNodeLocation nodeLocation = ifdefStmt.getNodeLocations()[0]; - inactiveCodeStart = nodeLocation.getNodeOffset(); + inactiveCodeStart = stmtLocation.getNodeOffset(); inInactiveCode = true; } } @@ -257,43 +270,36 @@ public class InactiveCodeHighlighting implements ICReconcilingListener { inactiveCodeStack.push(Boolean.valueOf(inInactiveCode)); if (!ifndefStmt.taken()) { if (!inInactiveCode) { - IASTNodeLocation nodeLocation = ifndefStmt.getNodeLocations()[0]; - inactiveCodeStart = nodeLocation.getNodeOffset(); + inactiveCodeStart = stmtLocation.getNodeOffset(); inInactiveCode = true; } } } else if (statement instanceof IASTPreprocessorElseStatement) { IASTPreprocessorElseStatement elseStmt = (IASTPreprocessorElseStatement)statement; if (!elseStmt.taken() && !inInactiveCode) { - IASTNodeLocation nodeLocation = elseStmt.getNodeLocations()[0]; - inactiveCodeStart = nodeLocation.getNodeOffset(); + inactiveCodeStart = stmtLocation.getNodeOffset(); inInactiveCode = true; } else if (elseStmt.taken() && inInactiveCode) { - IASTNodeLocation nodeLocation = elseStmt.getNodeLocations()[0]; - int inactiveCodeEnd = nodeLocation.getNodeOffset(); - positions.add(new HighlightPosition(inactiveCodeStart, inactiveCodeEnd - inactiveCodeStart, fHighlightKey)); + int inactiveCodeEnd = stmtLocation.getNodeOffset(); + positions.add(createHighlightPosition(inactiveCodeStart, inactiveCodeEnd, false, fHighlightKey)); inInactiveCode = false; } } else if (statement instanceof IASTPreprocessorElifStatement) { IASTPreprocessorElifStatement elifStmt = (IASTPreprocessorElifStatement)statement; if (!elifStmt.taken() && !inInactiveCode) { - IASTNodeLocation nodeLocation = elifStmt.getNodeLocations()[0]; - inactiveCodeStart = nodeLocation.getNodeOffset(); + inactiveCodeStart = stmtLocation.getNodeOffset(); inInactiveCode = true; } else if (elifStmt.taken() && inInactiveCode) { - IASTNodeLocation nodeLocation = elifStmt.getNodeLocations()[0]; - int inactiveCodeEnd = nodeLocation.getNodeOffset(); - positions.add(new HighlightPosition(inactiveCodeStart, inactiveCodeEnd - inactiveCodeStart, fHighlightKey)); + int inactiveCodeEnd = stmtLocation.getNodeOffset(); + positions.add(createHighlightPosition(inactiveCodeStart, inactiveCodeEnd, false, fHighlightKey)); inInactiveCode = false; } } else if (statement instanceof IASTPreprocessorEndifStatement) { - IASTPreprocessorEndifStatement endifStmt = (IASTPreprocessorEndifStatement)statement; try { boolean wasInInactiveCode = ((Boolean)inactiveCodeStack.pop()).booleanValue(); if (inInactiveCode && !wasInInactiveCode) { - IASTNodeLocation nodeLocation = endifStmt.getNodeLocations()[0]; - int inactiveCodeEnd = nodeLocation.getNodeOffset() + nodeLocation.getNodeLength(); - positions.add(new HighlightPosition(inactiveCodeStart, inactiveCodeEnd - inactiveCodeStart, fHighlightKey)); + int inactiveCodeEnd = stmtLocation.getNodeOffset() + stmtLocation.getNodeLength(); + positions.add(createHighlightPosition(inactiveCodeStart, inactiveCodeEnd, true, fHighlightKey)); } inInactiveCode = wasInInactiveCode; } @@ -306,4 +312,52 @@ public class InactiveCodeHighlighting implements ICReconcilingListener { return positions; } + /** + * Create a highlight position aligned to start at a line offset. The region's start is + * decreased to the line offset, and the end offset decreased to the line start if + * inclusive is false. + * + * @param startOffset the start offset of the region to align + * @param endOffset the (exclusive) end offset of the region to align + * @param inclusive whether the last line should be included or not + * @param key the highlight key + * @return a position aligned for background highlighting + */ + private HighlightPosition createHighlightPosition(int startOffset, int endOffset, boolean inclusive, String key) { + final IDocument document= fDocument; + try { + if (document != null) { + int start= document.getLineOfOffset(startOffset); + int end= document.getLineOfOffset(endOffset); + startOffset= document.getLineOffset(start); + if (!inclusive) { + endOffset= document.getLineOffset(end); + } + } + return new HighlightPosition(startOffset, endOffset - startOffset, key); + + } catch (BadLocationException x) { + // concurrent modification? + return null; + } + } + + /* + * @see org.eclipse.jface.text.ITextInputListener#inputDocumentAboutToBeChanged(org.eclipse.jface.text.IDocument, org.eclipse.jface.text.IDocument) + */ + public void inputDocumentAboutToBeChanged(IDocument oldInput, IDocument newInput) { + } + + /* + * @see org.eclipse.jface.text.ITextInputListener#inputDocumentChanged(org.eclipse.jface.text.IDocument, org.eclipse.jface.text.IDocument) + */ + public void inputDocumentChanged(IDocument oldInput, IDocument newInput) { + fDocument= newInput; + if (fEditor != null && fLineBackgroundPainter != null && !fLineBackgroundPainter.isDisposed()) { + List newInactiveCodePositions= Collections.EMPTY_LIST; + fLineBackgroundPainter.replaceHighlightPositions(fInactiveCodePositions, newInactiveCodePositions); + fInactiveCodePositions= newInactiveCodePositions; + } + } + } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/folding/DefaultCFoldingStructureProvider.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/folding/DefaultCFoldingStructureProvider.java index 76cf0388b7d..47c507c89c4 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/folding/DefaultCFoldingStructureProvider.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/folding/DefaultCFoldingStructureProvider.java @@ -651,6 +651,7 @@ public class DefaultCFoldingStructureProvider implements ICFoldingStructureProvi private static class Branch extends ModifiableRegion { private boolean fTaken; + public boolean fInclusive; /** * @param offset @@ -671,9 +672,6 @@ public class DefaultCFoldingStructureProvider implements ICFoldingStructureProvi fTaken= taken; } - /** - * @param endOffset - */ public void setEndOffset(int endOffset) { setLength(endOffset - getOffset()); } @@ -681,6 +679,10 @@ public class DefaultCFoldingStructureProvider implements ICFoldingStructureProvi public boolean taken() { return fTaken; } + + public void setInclusive(boolean inclusive) { + fInclusive= inclusive; + } } private final static boolean DEBUG= "true".equalsIgnoreCase(Platform.getDebugOption("org.eclipse.cdt.ui/debug/folding")); //$NON-NLS-1$//$NON-NLS-2$; @@ -1162,9 +1164,12 @@ public class DefaultCFoldingStructureProvider implements ICFoldingStructureProvi Branch branch= (Branch)branchStack.pop(); IASTPreprocessorElseStatement elseStmt = (IASTPreprocessorElseStatement)statement; branchStack.push(new Branch(stmtLocation.getNodeOffset(), elseStmt.taken())); - branch.setEndOffset(stmtLocation.getNodeOffset() - 1); - IRegion converted= converter != null ? converter.historicToActual(branch) : branch; - branches.add(new Branch(converted.getOffset(), converted.getLength(), branch.taken())); + branch.setEndOffset(stmtLocation.getNodeOffset()); + if (converter != null) { + IRegion converted= converter.historicToActual(branch); + branch= new Branch(converted.getOffset(), converted.getLength(), branch.taken()); + } + branches.add(branch); } else if (statement instanceof IASTPreprocessorElifStatement) { if (branchStack.isEmpty()) { // #elif without #if @@ -1173,9 +1178,12 @@ public class DefaultCFoldingStructureProvider implements ICFoldingStructureProvi Branch branch= (Branch)branchStack.pop(); IASTPreprocessorElifStatement elifStmt = (IASTPreprocessorElifStatement) statement; branchStack.push(new Branch(stmtLocation.getNodeOffset(), elifStmt.taken())); - branch.setEndOffset(stmtLocation.getNodeOffset() - 1); - IRegion converted= converter != null ? converter.historicToActual(branch) : branch; - branches.add(new Branch(converted.getOffset(), converted.getLength(), branch.taken())); + branch.setEndOffset(stmtLocation.getNodeOffset()); + if (converter != null) { + IRegion converted= converter.historicToActual(branch); + branch= new Branch(converted.getOffset(), converted.getLength(), branch.taken()); + } + branches.add(branch); } else if (statement instanceof IASTPreprocessorEndifStatement) { if (branchStack.isEmpty()) { // #endif without #if @@ -1183,13 +1191,17 @@ public class DefaultCFoldingStructureProvider implements ICFoldingStructureProvi } Branch branch= (Branch)branchStack.pop(); branch.setEndOffset(stmtLocation.getNodeOffset() + stmtLocation.getNodeLength()); - IRegion converted= converter != null ? converter.historicToActual(branch) : branch; - branches.add(new Branch(converted.getOffset(), converted.getLength(), branch.taken())); + if (converter != null) { + IRegion converted= converter.historicToActual(branch); + branch= new Branch(converted.getOffset(), converted.getLength(), branch.taken()); + } + branch.setInclusive(true); + branches.add(branch); } } for (Iterator iter = branches.iterator(); iter.hasNext(); ) { Branch branch= (Branch) iter.next(); - IRegion aligned = alignRegion(branch, ctx); + IRegion aligned = alignRegion(branch, ctx, branch.fInclusive); if (aligned != null) { Position alignedPos= new Position(aligned.getOffset(), aligned.getLength()); ctx.addProjectionRange(new CProjectionAnnotation(!branch.taken() && ctx.collapseInactiveCode(), computeKey(branch, ctx), false), alignedPos); @@ -1230,10 +1242,10 @@ public class DefaultCFoldingStructureProvider implements ICFoldingStructureProvi ITypedRegion partition = partitions[i]; boolean singleLine= false; if (ICPartitions.C_MULTI_LINE_COMMENT.equals(partition.getType())) { - Position position= createCommentPosition(alignRegion(partition, ctx)); + Position position= createCommentPosition(alignRegion(partition, ctx, true)); if (position != null) { if (startLine >= 0 && endLine - startLine >= fMinCommentLines) { - Position projection = createCommentPosition(alignRegion(commentRange, ctx)); + Position projection = createCommentPosition(alignRegion(commentRange, ctx, true)); if (projection != null) { comments.add(new Tuple(new CProjectionAnnotation(collapse, doc.get(projection.offset, Math.min(16, projection.length)), true), projection)); } @@ -1264,7 +1276,7 @@ public class DefaultCFoldingStructureProvider implements ICFoldingStructureProvi } if (startLine < 0 || lineNr - endLine > 1) { if (startLine >= 0 && endLine - startLine >= fMinCommentLines) { - Position projection = createCommentPosition(alignRegion(commentRange, ctx)); + Position projection = createCommentPosition(alignRegion(commentRange, ctx, true)); if (projection != null) { comments.add(new Tuple(new CProjectionAnnotation(collapse, doc.get(projection.offset, Math.min(16, projection.length)), true), projection)); } @@ -1281,7 +1293,7 @@ public class DefaultCFoldingStructureProvider implements ICFoldingStructureProvi } } if (startLine >= 0 && endLine - startLine >= fMinCommentLines) { - Position projection = createCommentPosition(alignRegion(commentRange, ctx)); + Position projection = createCommentPosition(alignRegion(commentRange, ctx, true)); if (projection != null) { comments.add(new Tuple(new CProjectionAnnotation(collapse, doc.get(projection.offset, Math.min(16, projection.length)), true), projection)); } @@ -1368,7 +1380,7 @@ public class DefaultCFoldingStructureProvider implements ICFoldingStructureProvi IRegion[] regions= computeProjectionRanges((ISourceReference) element, ctx); if (regions.length > 0) { - IRegion normalized= alignRegion(regions[regions.length - 1], ctx); + IRegion normalized= alignRegion(regions[regions.length - 1], ctx, true); if (normalized != null) { Position position= element instanceof IMember ? createMemberPosition(normalized, (IMember) element) : createCommentPosition(normalized); if (position != null) @@ -1405,7 +1417,7 @@ public class DefaultCFoldingStructureProvider implements ICFoldingStructureProvi /** * Creates a comment folding position from an - * {@link #alignRegion(IRegion, DefaultCFoldingStructureProvider.FoldingStructureComputationContext) aligned} + * {@link #alignRegion(IRegion, DefaultCFoldingStructureProvider.FoldingStructureComputationContext, boolean) aligned} * region. * * @param aligned an aligned region @@ -1420,7 +1432,7 @@ public class DefaultCFoldingStructureProvider implements ICFoldingStructureProvi /** * Creates a folding position that remembers its member from an - * {@link #alignRegion(IRegion, DefaultCFoldingStructureProvider.FoldingStructureComputationContext) aligned} + * {@link #alignRegion(IRegion, DefaultCFoldingStructureProvider.FoldingStructureComputationContext, boolean) aligned} * region. * * @param aligned an aligned region @@ -1445,6 +1457,24 @@ public class DefaultCFoldingStructureProvider implements ICFoldingStructureProvi * only one line) */ protected final IRegion alignRegion(IRegion region, FoldingStructureComputationContext ctx) { + return alignRegion(region, ctx, true); + } + + /** + * Aligns region to start and end at a line offset. The region's start is + * decreased to the next line offset, and the end offset increased to the next line start or the + * end of the document. null is returned if region is + * null itself or does not comprise at least one line delimiter, as a single line + * cannot be folded. + * + * @param region the region to align, may be null + * @param ctx the folding context + * @param inclusive include line of end offset + * @return a region equal or greater than region that is aligned with line + * offsets, null if the region is too small to be foldable (e.g. covers + * only one line) + */ + protected final IRegion alignRegion(IRegion region, FoldingStructureComputationContext ctx, boolean inclusive) { if (region == null) return null; @@ -1459,11 +1489,14 @@ public class DefaultCFoldingStructureProvider implements ICFoldingStructureProvi int offset= document.getLineOffset(start); int endOffset; - if (document.getNumberOfLines() > end + 1) - endOffset= document.getLineOffset(end + 1); - else - endOffset= document.getLineOffset(end) + document.getLineLength(end); - + if (inclusive) { + if (document.getNumberOfLines() > end + 1) + endOffset= document.getLineOffset(end + 1); + else + endOffset= document.getLineOffset(end) + document.getLineLength(end); + } else { + endOffset= document.getLineOffset(end); + } return new Region(offset, endOffset - offset); } catch (BadLocationException x) {