From b6f504aa9604aaf3451f8a300dd6b8f4d4d3f743 Mon Sep 17 00:00:00 2001 From: Anton Leherbauer Date: Fri, 18 Jan 2008 15:54:17 +0000 Subject: [PATCH] 23540: Add short cut for macro exploration --- core/org.eclipse.cdt.ui/plugin.properties | 3 + core/org.eclipse.cdt.ui/plugin.xml | 15 + .../cdt/internal/ui/editor/CEditor.java | 14 +- .../ui/editor/CEditorMessages.properties | 7 +- .../cdt/internal/ui/editor/CSourceViewer.java | 27 +- .../editor/ICEditorActionDefinitionIds.java | 8 + .../ui/text/CSourceViewerConfiguration.java | 46 ++- .../ui/text/c/hover/CMacroCompareViewer.java | 144 ++----- .../text/c/hover/CMacroExpansionControl.java | 2 +- .../CMacroExpansionExplorationControl.java | 80 ++-- .../ui/text/c/hover/CMacroExpansionHover.java | 386 +----------------- .../CMacroExpansionInformationProvider.java | 58 +++ .../ui/text/c/hover/CMacroExpansionInput.java | 346 +++++++++++++++- 13 files changed, 614 insertions(+), 522 deletions(-) create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CMacroExpansionInformationProvider.java diff --git a/core/org.eclipse.cdt.ui/plugin.properties b/core/org.eclipse.cdt.ui/plugin.properties index bc002fb1ff5..208a3c7409b 100644 --- a/core/org.eclipse.cdt.ui/plugin.properties +++ b/core/org.eclipse.cdt.ui/plugin.properties @@ -125,6 +125,9 @@ ActionDefinition.backwardMacroExpansion.description= Step backward in macro expa ActionDefinition.forwardMacroExpansion.name= Forward Macro Expansion ActionDefinition.forwardMacroExpansion.description= Step forward in macro expansions +ActionDefinition.showMacroExplorer.name= Explore Macro Expansion +ActionDefinition.showMacroExplorer.description= Opens a quick view for macro expansion exploration + CEditor.name=C/C++ Editor CPluginPreferencePage.name=C/C++ diff --git a/core/org.eclipse.cdt.ui/plugin.xml b/core/org.eclipse.cdt.ui/plugin.xml index fa05c7398bd..515eec9cd18 100644 --- a/core/org.eclipse.cdt.ui/plugin.xml +++ b/core/org.eclipse.cdt.ui/plugin.xml @@ -1480,6 +1480,16 @@ contextId="org.eclipse.cdt.ui.cEditorScope" commandId="org.eclipse.cdt.ui.edit.text.c.toggleMarkOccurrences" schemeId="org.eclipse.ui.defaultAcceleratorConfiguration"/> + + @@ -1638,6 +1648,11 @@ description="%toggleMarkOccurrences.description" categoryId="org.eclipse.cdt.ui.category.source" id="org.eclipse.cdt.ui.edit.text.c.toggleMarkOccurrences"/> + "org.eclipse.cdt.ui.edit.open.quick.macro.explorer"). + * @since 5.0 + */ + public static final String OPEN_QUICK_MACRO_EXPLORER = "org.eclipse.cdt.ui.edit.open.quick.macro.explorer"; //$NON-NLS-1$ } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/CSourceViewerConfiguration.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/CSourceViewerConfiguration.java index bba98eaa0c0..fd83c63a055 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/CSourceViewerConfiguration.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/CSourceViewerConfiguration.java @@ -85,6 +85,8 @@ import org.eclipse.cdt.internal.ui.editor.CElementHyperlinkDetector; import org.eclipse.cdt.internal.ui.text.c.hover.CEditorTextHoverDescriptor; import org.eclipse.cdt.internal.ui.text.c.hover.CEditorTextHoverProxy; import org.eclipse.cdt.internal.ui.text.c.hover.CInformationProvider; +import org.eclipse.cdt.internal.ui.text.c.hover.CMacroExpansionExplorationControl; +import org.eclipse.cdt.internal.ui.text.c.hover.CMacroExpansionInformationProvider; import org.eclipse.cdt.internal.ui.text.contentassist.CContentAssistProcessor; import org.eclipse.cdt.internal.ui.text.contentassist.ContentAssistPreference; import org.eclipse.cdt.internal.ui.text.correction.CCorrectionAssistant; @@ -230,8 +232,8 @@ public class CSourceViewerConfiguration extends TextSourceViewerConfiguration { } /** - * Creates outline presenter. - * @return Presenter with outline view. + * Creates type hierarchy presenter. + * @return Presenter with type hierarchy view. */ public IInformationPresenter getHierarchyPresenter(ISourceViewer sourceViewer) { final IInformationControlCreator hierarchyControlCreator = getHierarchyControlCreator(); @@ -833,4 +835,44 @@ public class CSourceViewerConfiguration extends TextSourceViewerConfiguration { fCodeScanner= null; fPreprocessorScanner= null; } + + /** + * Creates macro exploration presenter. + * @param sourceViewer + * @return Presenter with macro exploration view. + * + * @since 5.0 + */ + public IInformationPresenter getMacroExplorationPresenter(ISourceViewer sourceViewer) { + final IInformationControlCreator controlCreator= getMacroExplorationControlCreator(); + final InformationPresenter presenter = new InformationPresenter(controlCreator); + presenter.setDocumentPartitioning(getConfiguredDocumentPartitioning(sourceViewer)); + presenter.setAnchor(AbstractInformationControlManager.ANCHOR_GLOBAL); + final IInformationProvider provider = new CMacroExpansionInformationProvider(getEditor()); + presenter.setInformationProvider(provider, IDocument.DEFAULT_CONTENT_TYPE); + presenter.setInformationProvider(provider, ICPartitions.C_MULTI_LINE_COMMENT); + presenter.setInformationProvider(provider, ICPartitions.C_SINGLE_LINE_COMMENT); + presenter.setInformationProvider(provider, ICPartitions.C_STRING); + presenter.setInformationProvider(provider, ICPartitions.C_CHARACTER); + presenter.setInformationProvider(provider, ICPartitions.C_PREPROCESSOR); + presenter.setSizeConstraints(50, 20, true, false); + return presenter; + } + + /** + * Creates control for macro exploration in editor. + * @return Control. + */ + private IInformationControlCreator getMacroExplorationControlCreator() { + final IInformationControlCreator conrolCreator = new IInformationControlCreator() { + public IInformationControl createInformationControl(Shell parent) { + int shellStyle= SWT.RESIZE; + int textStyle= SWT.V_SCROLL | SWT.H_SCROLL; + return new CMacroExpansionExplorationControl(parent, shellStyle, textStyle); + } + }; + return conrolCreator; + } + + } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CMacroCompareViewer.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CMacroCompareViewer.java index 56c1f702712..4e2ffd22053 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CMacroCompareViewer.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CMacroCompareViewer.java @@ -51,20 +51,17 @@ class CMacroCompareViewer extends CMergeViewer { fBefore= before; } - public void setReplaceEdits(ReplaceEdit[] edits) { - int[] deltas= new int[edits.length]; - if (fBefore) { - for (int i= 1; i < edits.length; i++) { - ReplaceEdit edit= edits[i-1]; - deltas[i]= deltas[i-1] + (edit.getText().length() - edit.getLength()); - } - } + public void setReplaceEdits(int prefixLength, ReplaceEdit[] edits) { fStarts= new int[edits.length]; fLengths= new int[edits.length]; + int delta= 0; for (int i= 0; i < edits.length; i++) { ReplaceEdit edit= edits[i]; - fStarts[i]= edit.getOffset() + deltas[i]; + fStarts[i]= prefixLength + edit.getOffset() + delta; fLengths[i]= fBefore ? edit.getLength() : edit.getText().length(); + if (!fBefore) { + delta += edit.getText().length() - edit.getLength(); + } } } @@ -79,81 +76,6 @@ class CMacroCompareViewer extends CMergeViewer { } -// private class MacroExpansionComparator implements ITokenComparator { -// -// private final int[] fStarts; -// private final int[] fLengths; -// private int fCount; -// -// public MacroExpansionComparator(String text, ReplaceEdit[] edits, boolean before) { -// int[] deltas= new int[edits.length]; -// if (before) { -// for (int i= 1; i < edits.length; i++) { -// ReplaceEdit edit= edits[i-1]; -// deltas[i]= deltas[i-1] + (edit.getText().length() - edit.getLength()); -// } -// } -// fStarts= new int[edits.length * 2 + 1]; -// fLengths= new int[edits.length * 2 + 1]; -// int offset= 0; -// int i= 0; -// for (; i < edits.length; i++) { -// if (offset >= text.length()) { -// break; -// } -// fStarts[2*i]= offset; -// ReplaceEdit edit= edits[i]; -// fLengths[2*i]= edit.getOffset() + deltas[i] - offset; -// fStarts[2*i+1]= edit.getOffset() + deltas[i]; -// fLengths[2*i+1]= before ? edit.getLength() : edit.getText().length(); -// offset= fStarts[2*i+1] + fLengths[2*i+1]; -// } -// fCount= 2*i; -// -// if (offset < text.length()) { -// fStarts[fCount]= offset; -// fLengths[fCount]= text.length() - offset; -// fCount++; -// } -// } -// -// /* -// * @see org.eclipse.compare.contentmergeviewer.ITokenComparator#getTokenLength(int) -// */ -// public int getTokenLength(int index) { -// return fLengths[index]; -// } -// -// /* -// * @see org.eclipse.compare.contentmergeviewer.ITokenComparator#getTokenStart(int) -// */ -// public int getTokenStart(int index) { -// return fStarts[index]; -// } -// -// /* -// * @see org.eclipse.compare.rangedifferencer.IRangeComparator#getRangeCount() -// */ -// public int getRangeCount() { -// return fCount; -// } -// -// /* -// * @see org.eclipse.compare.rangedifferencer.IRangeComparator#rangesEqual(int, org.eclipse.compare.rangedifferencer.IRangeComparator, int) -// */ -// public boolean rangesEqual(int thisIndex, IRangeComparator other, int otherIndex) { -// return thisIndex == otherIndex && thisIndex % 2 == 0; -// } -// -// /* -// * @see org.eclipse.compare.rangedifferencer.IRangeComparator#skipRangeComparison(int, int, org.eclipse.compare.rangedifferencer.IRangeComparator) -// */ -// public boolean skipRangeComparison(int length, int maxLength, IRangeComparator other) { -// return false; -// } -// -// } - /** * A dummy {@link ITokenComparator}. */ @@ -175,16 +97,19 @@ class CMacroCompareViewer extends CMergeViewer { } } - TextViewer fLeftViewer; - TextViewer fRightViewer; - TextViewer fTopViewer; + private final ReplaceEditsHighlighter fLeftHighlighter; + private final ReplaceEditsHighlighter fRightHighlighter; + private Color fChangeBackground; + + private TextViewer fLeftViewer; + private TextViewer fRightViewer; + private TextViewer fTopViewer; - int fIndex; + private int fViewerIndex; + private CMacroExpansionInput fInput; private int fStepIndex; - private ReplaceEditsHighlighter fLeftHighlighter; - private ReplaceEditsHighlighter fRightHighlighter; - private Color fChangeBackground; + private int fPrefixLength; public CMacroCompareViewer(Composite parent, int styles, CompareConfiguration mp) { super(parent, styles, mp); @@ -196,7 +121,7 @@ class CMacroCompareViewer extends CMergeViewer { fChangeBackground= new Color(parent.getDisplay(), CHANGE_COLOR); fLeftViewer.addTextPresentationListener(fLeftHighlighter= new ReplaceEditsHighlighter(fChangeBackground, true)); fRightViewer.addTextPresentationListener(fRightHighlighter= new ReplaceEditsHighlighter(fChangeBackground, false)); - fIndex= 0; + fViewerIndex= 0; } /* @@ -221,7 +146,7 @@ class CMacroCompareViewer extends CMergeViewer { super.configureTextViewer(textViewer); // hack: gain access to text viewers - switch (fIndex++) { + switch (fViewerIndex++) { case 0: fTopViewer= textViewer; break; @@ -237,20 +162,17 @@ class CMacroCompareViewer extends CMergeViewer { * @see org.eclipse.compare.contentmergeviewer.TextMergeViewer#createTokenComparator(java.lang.String) */ protected ITokenComparator createTokenComparator(String line) { -// boolean before= fIndex++ % 2 != 0; -// final IMacroExpansionStep step; -// if (fStepIndex < fInput.fExplorer.getExpansionStepCount()) { -// step= fInput.fExplorer.getExpansionStep(fStepIndex); -// } else { -// before= !before; -// step= fInput.fExplorer.getFullExpansion(); -// } -// return new MacroExpansionComparator(line, step.getReplacements(), before); return new NullTokenComparator(); } + /** + * Set the macro expansion input. + * + * @param input + */ public void setMacroExpansionInput(CMacroExpansionInput input) { fInput= input; + fPrefixLength= fInput.getPrefix().length(); } /* @@ -261,25 +183,29 @@ class CMacroCompareViewer extends CMergeViewer { fRightViewer.setRedraw(false); final ReplaceEdit[] edits; + try { + final IMacroExpansionStep step; if (fStepIndex < fInput.fExplorer.getExpansionStepCount()) { - final IMacroExpansionStep step; step= fInput.fExplorer.getExpansionStep(fStepIndex); - edits= step.getReplacements(); } else { - edits= new ReplaceEdit[0]; + step= fInput.fExplorer.getFullExpansion(); } - fLeftHighlighter.setReplaceEdits(edits); - fRightHighlighter.setReplaceEdits(edits); + edits= step.getReplacements(); + + fLeftHighlighter.setReplaceEdits(fPrefixLength, edits); + fRightHighlighter.setReplaceEdits(fPrefixLength, edits); super.setInput(input); + } finally { fLeftViewer.setRedraw(true); fRightViewer.setRedraw(true); } if (edits.length > 0) { - fLeftViewer.revealRange(edits[0].getOffset(), edits[0].getLength()); - fRightViewer.revealRange(edits[0].getOffset(), edits[0].getText().length()); + final int firstDiffOffset= fPrefixLength + edits[0].getOffset(); + fLeftViewer.revealRange(firstDiffOffset, edits[0].getLength()); + fRightViewer.revealRange(firstDiffOffset, edits[0].getText().length()); } } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CMacroExpansionControl.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CMacroExpansionControl.java index 178a17d1b07..2c1b85bc781 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CMacroExpansionControl.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CMacroExpansionControl.java @@ -17,7 +17,7 @@ import org.eclipse.swt.widgets.Shell; import org.eclipse.cdt.internal.ui.text.AbstractSourceViewerInformationControl; /** - * Information control for macro expansion exploration. + * Information control for macro expansion. * * @since 5.0 */ diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CMacroExpansionExplorationControl.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CMacroExpansionExplorationControl.java index 59273b99963..f9601cde7b1 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CMacroExpansionExplorationControl.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CMacroExpansionExplorationControl.java @@ -110,6 +110,17 @@ public class CMacroExpansionExplorationControl extends AbstractCompareViewerInfo setMacroExpansionInput(input); } + /** + * Creates a new control for use as a "quick view" where the control immediately takes the focus. + * + * @param parent parent shell + * @param shellStyle shell style bits + * @param textStyle text viewer style bits + */ + public CMacroExpansionExplorationControl(Shell parent, int shellStyle, int textStyle) { + this(parent, shellStyle, textStyle, null); + } + /* * @see org.eclipse.cdt.internal.ui.text.AbstractSourceViewerInformationControl#hasHeader() */ @@ -171,13 +182,13 @@ public class CMacroExpansionExplorationControl extends AbstractCompareViewerInfo int result= super.open(); if (fInput != null) { - IHandler fBackwardHandler= new AbstractHandler() { + IHandler backwardHandler= new AbstractHandler() { public Object execute(ExecutionEvent event) throws ExecutionException { backward(); return null; } }; - IHandler fForwardHandler= new AbstractHandler() { + IHandler forwardHandler= new AbstractHandler() { public Object execute(ExecutionEvent event) throws ExecutionException { forward(); return null; @@ -189,8 +200,8 @@ public class CMacroExpansionExplorationControl extends AbstractCompareViewerInfo fContextService= (IContextService) workbench.getService(IContextService.class); fContextActivation= fContextService.activateContext(CONTEXT_ID_MACRO_EXPANSION_HOVER); fHandlerActivations= new ArrayList(); - fHandlerActivations.add(fHandlerService.activateHandler(COMMAND_ID_EXPANSION_BACK, fBackwardHandler)); - fHandlerActivations.add(fHandlerService.activateHandler(COMMAND_ID_EXPANSION_FORWARD, fForwardHandler)); + fHandlerActivations.add(fHandlerService.activateHandler(COMMAND_ID_EXPANSION_BACK, backwardHandler)); + fHandlerActivations.add(fHandlerService.activateHandler(COMMAND_ID_EXPANSION_FORWARD, forwardHandler)); String infoText= getInfoText(); if (infoText != null) { @@ -202,8 +213,8 @@ public class CMacroExpansionExplorationControl extends AbstractCompareViewerInfo } protected void forward() { - ++fIndex; - if (fIndex > fInput.fExplorer.getExpansionStepCount()) { + fIndex= fixIndex(fIndex + 1); + if (fIndex > getStepCount()) { fIndex= 0; } showExpansion(); @@ -212,7 +223,7 @@ public class CMacroExpansionExplorationControl extends AbstractCompareViewerInfo protected void backward() { --fIndex; if (fIndex < 0) { - fIndex = fInput.fExplorer.getExpansionStepCount(); + fIndex= fixIndex(getStepCount()); } showExpansion(); } @@ -278,37 +289,45 @@ public class CMacroExpansionExplorationControl extends AbstractCompareViewerInfo */ private void setMacroExpansionInput(CMacroExpansionInput input) { fInput= input; - fIndex= 0; - if (fMacroCompareViewer != null) { - fMacroCompareViewer.setMacroExpansionInput(fInput); + if (fInput != null) { + fIndex= fixIndex(input.fStartWithFullExpansion ? getStepCount() : 0); + showExpansion(); } - showExpansion(); + } + + private int fixIndex(int index) { + if (getStepCount() == 1 && index == 1) { + return 0; + } + return index; + } + + private int getStepCount() { + return fInput.fExplorer.getExpansionStepCount(); } private void showExpansion() { - final int idxLeft= fIndex; - final int idxRight= (fIndex + 1) % (fInput.fExplorer.getExpansionStepCount() + 1); + final int idxLeft= fIndex == getStepCount() ? 0 : fIndex; + final int idxRight= fIndex + 1; CompareConfiguration config= getCompareConfiguration(); - config.setAncestorLabel(getLabelForIndex(0)); config.setLeftLabel(getLabelForIndex(idxLeft)); config.setRightLabel(getLabelForIndex(idxRight)); - final ITypedElement original= getContentForIndex(0); - final ITypedElement left= getContentForIndex(idxLeft); - final ITypedElement right= getContentForIndex(idxRight); + final ITypedElement left= getContentForIndex(fIndex, true); + final ITypedElement right= getContentForIndex(fIndex, false); setTitleText(CHoverMessages.CMacroExpansionControl_title_macroExpansion); fMacroViewer.getDocument().set(getMacroText(fIndex)); - setInput(createCompareInput(original, left, right)); + setInput(createCompareInput(null, left, right)); } private String getLabelForIndex(int index) { if (index == 0) { return CHoverMessages.CMacroExpansionControl_title_original; - } else if (index < fInput.fExplorer.getExpansionStepCount()) { + } else if (index < getStepCount()) { return NLS.bind(CHoverMessages.CMacroExpansionControl_title_expansion, - String.valueOf(index), String.valueOf(fInput.fExplorer.getExpansionStepCount())); + String.valueOf(index), String.valueOf(getStepCount())); } else { return CHoverMessages.CMacroExpansionControl_title_fullyExpanded; } @@ -318,12 +337,20 @@ public class CMacroExpansionExplorationControl extends AbstractCompareViewerInfo return d.findDifferences(false, new NullProgressMonitor(), null, original, left, right); } - private ITypedElement getContentForIndex(int index) { - final String text; - if (index < fInput.fExplorer.getExpansionStepCount()) { - text= fInput.fExplorer.getExpansionStep(index).getCodeBeforeStep(); + private ITypedElement getContentForIndex(int index, boolean before) { + final IMacroExpansionStep expansionStep; + if (index < getStepCount()) { + expansionStep= fInput.fExplorer.getExpansionStep(index); } else { - text= fInput.fExplorer.getFullExpansion().getCodeAfterStep(); + expansionStep= fInput.fExplorer.getFullExpansion(); + } + final String text; + final String prefix = fInput.getPrefix(); + final String postfix = fInput.getPostfix(); + if (before) { + text= prefix + expansionStep.getCodeBeforeStep() + postfix; + } else { + text= prefix + expansionStep.getCodeAfterStep() + postfix; } final Document doc= new Document(text); CUIPlugin.getDefault().getTextTools().setupCDocument(doc); @@ -332,7 +359,8 @@ public class CMacroExpansionExplorationControl extends AbstractCompareViewerInfo private String getMacroText(int index) { final String text; - if (index < fInput.fExplorer.getExpansionStepCount()) { + final int count= getStepCount(); + if (index < count) { final IMacroExpansionStep expansionStep= fInput.fExplorer.getExpansionStep(index); IMacroBinding binding= expansionStep.getExpandedMacro(); StringBuffer buffer= new StringBuffer(); diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CMacroExpansionHover.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CMacroExpansionHover.java index a1e52cfab38..05d437847b8 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CMacroExpansionHover.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CMacroExpansionHover.java @@ -13,55 +13,19 @@ package org.eclipse.cdt.internal.ui.text.c.hover; import java.lang.ref.Reference; import java.lang.ref.SoftReference; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.NullProgressMonitor; -import org.eclipse.core.runtime.Status; -import org.eclipse.jface.text.BadLocationException; -import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IInformationControl; import org.eclipse.jface.text.IInformationControlCreator; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextSelection; import org.eclipse.jface.text.ITextViewer; -import org.eclipse.jface.text.Position; import org.eclipse.jface.text.Region; import org.eclipse.jface.text.information.IInformationProviderExtension2; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionProvider; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Shell; -import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorPart; -import org.eclipse.ui.texteditor.ITextEditor; - -import org.eclipse.cdt.core.dom.ast.ASTVisitor; -import org.eclipse.cdt.core.dom.ast.IASTDeclaration; -import org.eclipse.cdt.core.dom.ast.IASTExpression; -import org.eclipse.cdt.core.dom.ast.IASTFileLocation; -import org.eclipse.cdt.core.dom.ast.IASTMacroExpansion; -import org.eclipse.cdt.core.dom.ast.IASTName; -import org.eclipse.cdt.core.dom.ast.IASTNode; -import org.eclipse.cdt.core.dom.ast.IASTNodeLocation; -import org.eclipse.cdt.core.dom.ast.IASTStatement; -import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; -import org.eclipse.cdt.core.dom.ast.IBinding; -import org.eclipse.cdt.core.dom.ast.IMacroBinding; -import org.eclipse.cdt.core.dom.rewrite.MacroExpansionExplorer; -import org.eclipse.cdt.core.model.ILanguage; -import org.eclipse.cdt.core.model.ITranslationUnit; -import org.eclipse.cdt.core.model.IWorkingCopy; -import org.eclipse.cdt.ui.CUIPlugin; -import org.eclipse.cdt.ui.IWorkingCopyManager; - -import org.eclipse.cdt.internal.core.model.ASTCache.ASTRunnable; - -import org.eclipse.cdt.internal.ui.editor.ASTProvider; /** * A hover to explore macro expansion. @@ -70,353 +34,26 @@ import org.eclipse.cdt.internal.ui.editor.ASTProvider; */ public class CMacroExpansionHover extends AbstractCEditorTextHover implements IInformationProviderExtension2 { - /** - * AST visitor to find a node (declaration, statement or expression) enclosing a given source range. - */ - private static class FindEnclosingNodeAction extends ASTVisitor { - { - shouldVisitTranslationUnit= true; - shouldVisitDeclarations = true; - shouldVisitStatements = true; - shouldVisitExpressions = true; - } - - private final int fOffset; - private final int fEndOffset; - private final String fFilePath; - private IASTNode fBestMatch= null; - private int fBestOffset= -1; - private int fBestEndOffset= Integer.MAX_VALUE; - - public FindEnclosingNodeAction(String filePath, int offset, int length) { - fFilePath= filePath; - fOffset= offset; - fEndOffset= offset + length; - } - - private int processNode(IASTNode node) { - IASTFileLocation location= node.getFileLocation(); - if (location != null && fFilePath.equals(location.getFileName())) { - final int startOffset = location.getNodeOffset(); - if (startOffset <= fOffset) { - int endOffset= startOffset + location.getNodeLength(); - if (endOffset >= fEndOffset) { - if (startOffset > fBestOffset || endOffset < fBestEndOffset) { - fBestMatch= node; - fBestOffset= startOffset; - fBestEndOffset= endOffset; - boolean isPerfectMatch= startOffset == fOffset || endOffset == fEndOffset; - if (isPerfectMatch) { - return PROCESS_ABORT; - } - } - } else { - return PROCESS_SKIP; - } - } else { - return PROCESS_ABORT; - } - } - return PROCESS_CONTINUE; - } - - public int visit(IASTTranslationUnit tu) { - return processNode(tu); - } - - public int visit(IASTDeclaration declaration) { - return processNode(declaration); - } - - public int visit(IASTExpression expression) { - return processNode(expression); - } - - public int visit(IASTStatement statement) { - return processNode(statement); - } - - public IASTNode getNode() { - return fBestMatch; - } - } - - /** - * AST visitor to collect nodes (declaration, statement or expression) enclosed in a given source range. - */ - private static class CollectEnclosedNodesAction extends ASTVisitor { - { - shouldVisitDeclarations = true; - shouldVisitStatements = true; - shouldVisitExpressions = true; - } - - private final int fOffset; - private final int fEndOffset; - private final String fFilePath; - private List fMatches= new ArrayList(); - - public CollectEnclosedNodesAction(String filePath, int offset, int length) { - fFilePath= filePath; - fOffset= offset; - fEndOffset= offset + length; - } - - private int processNode(IASTNode node) { - IASTFileLocation location= node.getFileLocation(); - if (location != null && fFilePath.equals(location.getFileName())) { - final int startOffset = location.getNodeOffset(); - if (startOffset >= fOffset) { - int endOffset= startOffset + location.getNodeLength(); - if (endOffset <= fEndOffset) { - fMatches.add(node); - } else { - return PROCESS_SKIP; - } - } else if (startOffset >= fEndOffset) { - return PROCESS_ABORT; - } - } - return PROCESS_CONTINUE; - } - - public int visit(IASTTranslationUnit tu) { - return processNode(tu); - } - - public int visit(IASTDeclaration declaration) { - return processNode(declaration); - } - - public int visit(IASTExpression expression) { - return processNode(expression); - } - - public int visit(IASTStatement statement) { - return processNode(statement); - } - - public Collection getNodes() { - return fMatches; - } - } - - /** - * Computes the source location for a given identifier. - */ - private static class ComputeExpansionRegionRunnable implements ASTRunnable { - private final Position fTextRegion; - private final boolean fAllowSelection; - private IASTNode fEnclosingNode; - private List fExpansionNodes= new ArrayList(); - private MacroExpansionExplorer fExplorer; - - private ComputeExpansionRegionRunnable(ITranslationUnit tUnit, IRegion textRegion, boolean allowSelection) { - fTextRegion= new Position(textRegion.getOffset(), textRegion.getLength()); - fAllowSelection= allowSelection; - } - - /* - * @see org.eclipse.cdt.internal.core.model.ASTCache.ASTRunnable#runOnAST(org.eclipse.cdt.core.dom.ast.IASTTranslationUnit) - */ - public IStatus runOnAST(ILanguage lang, IASTTranslationUnit ast) { - if (ast != null) { - // try macro name match first - IASTNode node= ast.selectNodeForLocation(ast.getFilePath(), fTextRegion.getOffset(), fTextRegion.getLength()); - if (node instanceof IASTName) { - IASTName macroName= (IASTName) node; - IBinding binding= macroName.getBinding(); - if (binding instanceof IMacroBinding) { - addExpansionNode(node); - createMacroExpansionExplorer(ast, getExpansionRegion()); - return Status.OK_STATUS; - } - } - if (fAllowSelection) { - // selection - FindEnclosingNodeAction nodeFinder= new FindEnclosingNodeAction(ast.getFilePath(), fTextRegion.getOffset(), fTextRegion.getLength()); - ast.accept(nodeFinder); - fEnclosingNode= nodeFinder.getNode(); - if (fEnclosingNode != null) { - boolean macroOccurrence= false; - IASTNodeLocation[] locations= fEnclosingNode.getNodeLocations(); - for (int i = 0; i < locations.length; i++) { - IASTNodeLocation location= locations[i]; - if (location instanceof IASTMacroExpansion) { - IASTFileLocation fileLocation= location.asFileLocation(); - if (fileLocation != null && ast.getFilePath().equals(fileLocation.getFileName())) { - if (fTextRegion.overlapsWith(fileLocation.getNodeOffset(), fileLocation.getNodeLength())) { - nodeFinder= new FindEnclosingNodeAction(ast.getFilePath(), fileLocation.getNodeOffset(), fileLocation.getNodeLength()); - ast.accept(nodeFinder); - addExpansionNode(nodeFinder.getNode()); - macroOccurrence= true; - } - } - } - } - if (macroOccurrence) { - CollectEnclosedNodesAction nodeCollector= new CollectEnclosedNodesAction(ast.getFilePath(), fTextRegion.getOffset(), fTextRegion.getLength()); - ast.accept(nodeCollector); - fExpansionNodes.addAll(nodeCollector.getNodes()); - createMacroExpansionExplorer(ast, getExpansionRegion()); - return Status.OK_STATUS; - } - } - } - } - return Status.CANCEL_STATUS; - } - - private void createMacroExpansionExplorer(IASTTranslationUnit ast, IRegion region) { - if (region != null) { - fExplorer= MacroExpansionExplorer.create(ast, region); - } - } - - private void addExpansionNode(IASTNode node) { - if (node != null) { - fEnclosingNode= computeCommonAncestor(node, fEnclosingNode); - fExpansionNodes.add(node); - } - } - - private IASTNode computeCommonAncestor(IASTNode node, IASTNode other) { - if (node == null) { - return null; - } - if (other == null) { - return node; - } - if (node == other) { - return other; - } - List ancestors= new ArrayList(); - while (node != null) { - node= node.getParent(); - ancestors.add(node); - } - while (other != null) { - if (ancestors.contains(other)) { - return other; - } - other= other.getParent(); - } - return null; - } - - IRegion getExpansionRegion() { - if (fEnclosingNode != null) { - int startOffset= Integer.MAX_VALUE; - int endOffset= 0; - for (Iterator it= fExpansionNodes.iterator(); it.hasNext(); ) { - IASTNode node= (IASTNode) it.next(); - if (node != fEnclosingNode) { - while (node != null && node.getParent() != fEnclosingNode) { - node= node.getParent(); - } - } - if (node != null) { - IASTFileLocation location= node.getFileLocation(); - if (location != null) { - startOffset= Math.min(startOffset, location.getNodeOffset()); - endOffset= Math.max(endOffset, location.getNodeOffset() + location.getNodeLength()); - } - } - } - if (endOffset > startOffset) { - return new Region(startOffset, endOffset - startOffset); - } - } - return null; - } - - IASTNode getEnclosingNode() { - return fEnclosingNode; - } - - MacroExpansionExplorer getMacroExpansionExplorer() { - return fExplorer; - } - } - private Reference fCache; /* * @see org.eclipse.cdt.internal.ui.text.c.hover.AbstractCEditorTextHover#getHoverInfo(org.eclipse.jface.text.ITextViewer, org.eclipse.jface.text.IRegion) */ public String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion) { - CMacroExpansionInput input= createMacroExpansionInput(getEditor(), hoverRegion, true); + CMacroExpansionInput input= CMacroExpansionInput.create(getEditor(), hoverRegion, false); if (input == null) { return null; } + input.fStartWithFullExpansion= true; fCache= new SoftReference(input); - return input.fExplorer.getFullExpansion().getCodeAfterStep(); + String result= input.fExplorer.getFullExpansion().getCodeAfterStep(); + if (result.length() == 0) { + // expansion is empty - hover should show empty string + result= "/* EMPTY */"; //$NON-NLS-1$ + } + return result; } - public static CMacroExpansionInput createMacroExpansionInput(IEditorPart editor, IRegion hoverRegion, boolean allowSelection) { - if (editor == null || !(editor instanceof ITextEditor)) { - return null; - } - IEditorInput editorInput= editor.getEditorInput(); - IWorkingCopyManager manager= CUIPlugin.getDefault().getWorkingCopyManager(); - IWorkingCopy tu = manager.getWorkingCopy(editorInput); - if (tu == null) { - return null; - } - - IProgressMonitor monitor= new NullProgressMonitor(); - ComputeExpansionRegionRunnable computer= new ComputeExpansionRegionRunnable(tu, hoverRegion, allowSelection); - IStatus status= ASTProvider.getASTProvider().runOnAST(tu, ASTProvider.WAIT_ACTIVE_ONLY, monitor, computer); - if (!status.isOK()) { - return null; - } - IRegion region= computer.getExpansionRegion(); - if (region == null) { - return null; - } - MacroExpansionExplorer explorer= computer.getMacroExpansionExplorer(); - if (explorer == null) { - return null; - } - ITextEditor textEditor= (ITextEditor)editor; - IDocument document= textEditor.getDocumentProvider().getDocument(editorInput); - region= alignRegion(region, document); - - CMacroExpansionInput input= new CMacroExpansionInput(); - input.fExplorer= explorer; - input.fDocument= document; - input.fRegion= region; - return input; - } - - private static final IRegion alignRegion(IRegion region, IDocument document) { - try { - int start= document.getLineOfOffset(region.getOffset()); - int end= document.getLineOfOffset(region.getOffset() + region.getLength()); - if (start == end) { - return region; - } - int offset= document.getLineOffset(start); - if (document.get(offset, region.getOffset()- offset).trim().length() > 0) { - offset= region.getOffset(); - } - int endOffset; - if (document.getNumberOfLines() > end + 1) { - endOffset= document.getLineOffset(end + 1); - } else { - endOffset= document.getLineOffset(end) + document.getLineLength(end); - } - int oldEndOffset= region.getOffset() + region.getLength(); - if (document.get(oldEndOffset, endOffset - oldEndOffset).trim().length() > 0) { - endOffset= oldEndOffset; - } - return new Region(offset, endOffset - offset); - - } catch (BadLocationException x) { - return region; - } - } - /* * @see org.eclipse.jface.text.ITextHoverExtension#getHoverControlCreator() */ @@ -436,12 +73,12 @@ public class CMacroExpansionHover extends AbstractCEditorTextHover implements II public IInformationControl createInformationControl(Shell parent) { int shellStyle= SWT.RESIZE; int style= SWT.V_SCROLL | SWT.H_SCROLL; - return new CMacroExpansionExplorationControl(parent, shellStyle, style, getMacroExpansionInput()); + return new CMacroExpansionExplorationControl(parent, shellStyle, style, getCachedMacroExpansionInput()); } }; } - protected CMacroExpansionInput getMacroExpansionInput() { + protected CMacroExpansionInput getCachedMacroExpansionInput() { if (fCache == null) { return null; } @@ -455,7 +92,8 @@ public class CMacroExpansionHover extends AbstractCEditorTextHover implements II if (selection instanceof ITextSelection) { ITextSelection textSelection= (ITextSelection) selection; IRegion region= new Region(textSelection.getOffset(), textSelection.getLength()); - input= createMacroExpansionInput(editor, region, true); + input= CMacroExpansionInput.create(editor, region, true); + input.fStartWithFullExpansion= true; } } } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CMacroExpansionInformationProvider.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CMacroExpansionInformationProvider.java new file mode 100644 index 00000000000..8fc07a87837 --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CMacroExpansionInformationProvider.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2008 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Anton Leherbauer (Wind River Systems) - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.internal.ui.text.c.hover; + +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.Region; +import org.eclipse.jface.text.information.IInformationProvider; +import org.eclipse.jface.text.information.IInformationProviderExtension; +import org.eclipse.swt.graphics.Point; +import org.eclipse.ui.texteditor.ITextEditor; + + +/** + * Information provider for macro exploration. + * + * @since 5.0 + */ +public class CMacroExpansionInformationProvider implements IInformationProvider, IInformationProviderExtension { + + private final ITextEditor fEditor; + + public CMacroExpansionInformationProvider(ITextEditor editor) { + fEditor= editor; + } + + /* + * @see org.eclipse.jface.text.information.IInformationProvider#getInformation(org.eclipse.jface.text.ITextViewer, org.eclipse.jface.text.IRegion) + */ + public String getInformation(ITextViewer textViewer, IRegion subject) { + return null; + } + + /* + * @see org.eclipse.jface.text.information.IInformationProvider#getSubject(org.eclipse.jface.text.ITextViewer, int) + */ + public IRegion getSubject(ITextViewer textViewer, int offset) { + Point selection= textViewer.getSelectedRange(); + return new Region(selection.x, selection.y); + } + + /* + * @see org.eclipse.jface.text.information.IInformationProviderExtension#getInformation2(org.eclipse.jface.text.ITextViewer, org.eclipse.jface.text.IRegion) + */ + public Object getInformation2(ITextViewer textViewer, IRegion subject) { + return CMacroExpansionInput.create(fEditor, subject, true); + } + +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CMacroExpansionInput.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CMacroExpansionInput.java index 35273705a69..92712588fa2 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CMacroExpansionInput.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CMacroExpansionInput.java @@ -11,18 +11,362 @@ package org.eclipse.cdt.internal.ui.text.c.hover; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.Status; +import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.Position; +import org.eclipse.jface.text.Region; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.texteditor.ITextEditor; +import org.eclipse.cdt.core.dom.ast.ASTVisitor; +import org.eclipse.cdt.core.dom.ast.IASTDeclaration; +import org.eclipse.cdt.core.dom.ast.IASTExpression; +import org.eclipse.cdt.core.dom.ast.IASTFileLocation; +import org.eclipse.cdt.core.dom.ast.IASTMacroExpansion; +import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.dom.ast.IASTNodeLocation; +import org.eclipse.cdt.core.dom.ast.IASTStatement; +import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; +import org.eclipse.cdt.core.dom.ast.IBinding; +import org.eclipse.cdt.core.dom.ast.IMacroBinding; import org.eclipse.cdt.core.dom.rewrite.MacroExpansionExplorer; +import org.eclipse.cdt.core.model.ILanguage; +import org.eclipse.cdt.core.model.ITranslationUnit; +import org.eclipse.cdt.core.model.IWorkingCopy; +import org.eclipse.cdt.ui.CUIPlugin; +import org.eclipse.cdt.ui.IWorkingCopyManager; + +import org.eclipse.cdt.internal.core.model.ASTCache.ASTRunnable; + +import org.eclipse.cdt.internal.ui.editor.ASTProvider; +import org.eclipse.cdt.internal.ui.text.CHeuristicScanner; /** * An input object to the {@link CMacroExpansionExplorationControl}. * * @since 5.0 */ -class CMacroExpansionInput { +public class CMacroExpansionInput { + + /** + * AST visitor to find a node (declaration, statement or expression) enclosing a given source range. + */ + private static class FindEnclosingNodeAction extends ASTVisitor { + { + shouldVisitTranslationUnit= true; + shouldVisitDeclarations = true; + shouldVisitStatements = true; + shouldVisitExpressions = true; + } + + private final int fOffset; + private final int fEndOffset; + private final String fFilePath; + private IASTNode fBestMatch= null; + private int fBestOffset= -1; + private int fBestEndOffset= Integer.MAX_VALUE; + + public FindEnclosingNodeAction(String filePath, int offset, int length) { + fFilePath= filePath; + fOffset= offset; + fEndOffset= offset + length; + } + + private int processNode(IASTNode node) { + IASTFileLocation location= node.getFileLocation(); + if (location != null && fFilePath.equals(location.getFileName())) { + final int startOffset = location.getNodeOffset(); + if (startOffset <= fOffset) { + int endOffset= startOffset + location.getNodeLength(); + if (endOffset >= fEndOffset) { + if (startOffset > fBestOffset || endOffset < fBestEndOffset) { + fBestMatch= node; + fBestOffset= startOffset; + fBestEndOffset= endOffset; + boolean isPerfectMatch= startOffset == fOffset || endOffset == fEndOffset; + if (isPerfectMatch) { + return PROCESS_ABORT; + } + } + } else { + return PROCESS_SKIP; + } + } else { + return PROCESS_ABORT; + } + } + return PROCESS_CONTINUE; + } + + public int visit(IASTTranslationUnit tu) { + return processNode(tu); + } + + public int visit(IASTDeclaration declaration) { + return processNode(declaration); + } + + public int visit(IASTExpression expression) { + return processNode(expression); + } + + public int visit(IASTStatement statement) { + return processNode(statement); + } + + public IASTNode getNode() { + return fBestMatch; + } + } + + /** + * Computes the expansion region for a selection. + */ + private static class ExpansionRegionComputer implements ASTRunnable { + private final Position fTextRegion; + private final boolean fAllowSelection; + private IASTNode fEnclosingNode; + private List fExpansionNodes= new ArrayList(); + private MacroExpansionExplorer fExplorer; + private IRegion fExpansionRegion; + + private ExpansionRegionComputer(ITranslationUnit tUnit, IRegion textRegion, boolean allowSelection) { + fTextRegion= new Position(textRegion.getOffset(), textRegion.getLength()); + fAllowSelection= allowSelection; + } + + /* + * @see org.eclipse.cdt.internal.core.model.ASTCache.ASTRunnable#runOnAST(org.eclipse.cdt.core.dom.ast.IASTTranslationUnit) + */ + public IStatus runOnAST(ILanguage lang, IASTTranslationUnit ast) { + if (ast != null) { + // try macro name match first + IASTNode node= ast.selectNodeForLocation(ast.getFilePath(), fTextRegion.getOffset(), fTextRegion.getLength()); + if (node instanceof IASTName) { + IASTName macroName= (IASTName) node; + IBinding binding= macroName.getBinding(); + if (binding instanceof IMacroBinding && !macroName.isDefinition()) { + addExpansionNode(node); + createMacroExpansionExplorer(ast); + return Status.OK_STATUS; + } + } + if (fAllowSelection) { + // selection + FindEnclosingNodeAction nodeFinder= new FindEnclosingNodeAction(ast.getFilePath(), fTextRegion.getOffset(), fTextRegion.getLength()); + ast.accept(nodeFinder); + fEnclosingNode= nodeFinder.getNode(); + if (fEnclosingNode != null) { + boolean macroOccurrence= false; + IASTNodeLocation[] locations= fEnclosingNode.getNodeLocations(); + for (int i = 0; i < locations.length; i++) { + IASTNodeLocation location= locations[i]; + if (location instanceof IASTMacroExpansion) { + IASTFileLocation fileLocation= location.asFileLocation(); + if (fileLocation != null && ast.getFilePath().equals(fileLocation.getFileName())) { + if (fTextRegion.overlapsWith(fileLocation.getNodeOffset(), fileLocation.getNodeLength())) { + nodeFinder= new FindEnclosingNodeAction(ast.getFilePath(), fileLocation.getNodeOffset(), fileLocation.getNodeLength()); + ast.accept(nodeFinder); + addExpansionNode(nodeFinder.getNode()); + macroOccurrence= true; + } + } + } + } + if (macroOccurrence) { + createMacroExpansionExplorer(ast); + return Status.OK_STATUS; + } + } + } + } + return Status.CANCEL_STATUS; + } + + private void createMacroExpansionExplorer(IASTTranslationUnit ast) { + IRegion region= getExpansionRegion(); + if (region != null) { + fExplorer= MacroExpansionExplorer.create(ast, region); + int length= fExplorer.getExpansionStep(0).getCodeAfterStep().length(); + if (region.getLength() < length) { + region= new Region(region.getOffset(), length); + } + fExpansionRegion= region; + } + } + + private void addExpansionNode(IASTNode node) { + if (node != null) { + fEnclosingNode= computeCommonAncestor(node, fEnclosingNode); + fExpansionNodes.add(node); + } + } + + private IASTNode computeCommonAncestor(IASTNode node, IASTNode other) { + if (node == null) { + return null; + } + if (other == null) { + return node; + } + if (node == other) { + return other; + } + List ancestors= new ArrayList(); + while (node != null) { + node= node.getParent(); + ancestors.add(node); + } + while (other != null) { + if (ancestors.contains(other)) { + return other; + } + other= other.getParent(); + } + return null; + } + + IRegion getExpansionRegion() { + if (fExpansionRegion != null) + return fExpansionRegion; + if (fEnclosingNode != null) { + int startOffset= Integer.MAX_VALUE; + int endOffset= fTextRegion.getOffset() + fTextRegion.getLength(); + for (Iterator it= fExpansionNodes.iterator(); it.hasNext(); ) { + IASTNode node= (IASTNode) it.next(); + if (node != fEnclosingNode) { + while (node != null && node.getParent() != fEnclosingNode) { + node= node.getParent(); + } + } + if (node != null) { + IASTFileLocation location= node.getFileLocation(); + if (location != null) { + startOffset= Math.min(startOffset, location.getNodeOffset()); + endOffset= Math.max(endOffset, location.getNodeOffset() + location.getNodeLength()); + } + } + } + if (endOffset > startOffset) { + startOffset= Math.min(startOffset, fTextRegion.getOffset()); + return new Region(startOffset, endOffset - startOffset); + } + } + return null; + } + + IASTNode getEnclosingNode() { + return fEnclosingNode; + } + + MacroExpansionExplorer getMacroExpansionExplorer() { + return fExplorer; + } + } + MacroExpansionExplorer fExplorer; IDocument fDocument; IRegion fRegion; + boolean fStartWithFullExpansion; + + private int fPrefixLength; + private int fPostfixLength; + + private CMacroExpansionInput() { + // forbidden + } + + String getPrefix() { + try { + return fDocument.get(fRegion.getOffset() - fPrefixLength, fPrefixLength); + } catch (BadLocationException exc) { + fPrefixLength= 0; + return ""; //$NON-NLS-1$ + } + } + + String getPostfix() { + try { + return fDocument.get(fRegion.getOffset() + fRegion.getLength(), fPostfixLength); + } catch (BadLocationException exc) { + fPostfixLength= 0; + return ""; //$NON-NLS-1$ + } + } + + public static CMacroExpansionInput create(IEditorPart editor, IRegion hoverRegion, boolean allowSelection) { + if (editor == null || !(editor instanceof ITextEditor)) { + return null; + } + IEditorInput editorInput= editor.getEditorInput(); + IWorkingCopyManager manager= CUIPlugin.getDefault().getWorkingCopyManager(); + IWorkingCopy tu = manager.getWorkingCopy(editorInput); + if (tu == null) { + return null; + } + + IProgressMonitor monitor= new NullProgressMonitor(); + ExpansionRegionComputer computer= new ExpansionRegionComputer(tu, hoverRegion, allowSelection); + IStatus status= ASTProvider.getASTProvider().runOnAST(tu, ASTProvider.WAIT_ACTIVE_ONLY, monitor, computer); + if (!status.isOK()) { + return null; + } + IRegion region= computer.getExpansionRegion(); + if (region == null) { + return null; + } + MacroExpansionExplorer explorer= computer.getMacroExpansionExplorer(); + if (explorer == null) { + return null; + } + ITextEditor textEditor= (ITextEditor)editor; + IDocument document= textEditor.getDocumentProvider().getDocument(editorInput); + + CMacroExpansionInput input= new CMacroExpansionInput(); + input.fExplorer= explorer; + input.fDocument= document; + input.fRegion= region; + + // add context lines +// IRegion contextRegion= expandRegion(region, document, 2); +// input.fPrefixLength= region.getOffset() - contextRegion.getOffset(); +// input.fPostfixLength= contextRegion.getOffset() + contextRegion.getLength() - (region.getOffset() + region.getLength()); + return input; + } + + public static final IRegion expandRegion(IRegion region, IDocument document, int contextLines) { + try { + int start= document.getLineOfOffset(region.getOffset()); + start= Math.max(start - contextLines, 0); + int offset= document.getLineOffset(start); + CHeuristicScanner scanner= new CHeuristicScanner(document); + offset= scanner.findNonWhitespaceForward(offset, region.getOffset() + 1); + + int end= document.getLineOfOffset(region.getOffset() + region.getLength()); + end= Math.min(end + contextLines, document.getNumberOfLines() - 1); + + final int endOffset; + if (document.getNumberOfLines() > end + 1) { + endOffset= document.getLineOffset(end + 1); + } else { + endOffset= document.getLineOffset(end) + document.getLineLength(end); + } + return new Region(offset, endOffset - offset); + + } catch (BadLocationException x) { + return region; + } + } + }