mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-07-23 00:45:28 +02:00
23540: Add short cut for macro exploration
This commit is contained in:
parent
d41fb1782b
commit
b6f504aa96
13 changed files with 614 additions and 522 deletions
|
@ -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++
|
||||
|
|
|
@ -1480,6 +1480,16 @@
|
|||
contextId="org.eclipse.cdt.ui.cEditorScope"
|
||||
commandId="org.eclipse.cdt.ui.edit.text.c.toggleMarkOccurrences"
|
||||
schemeId="org.eclipse.ui.defaultAcceleratorConfiguration"/>
|
||||
<key
|
||||
sequence="M1+="
|
||||
contextId="org.eclipse.cdt.ui.cEditorScope"
|
||||
commandId="org.eclipse.cdt.ui.edit.open.quick.macro.explorer"
|
||||
schemeId="org.eclipse.ui.defaultAcceleratorConfiguration"/>
|
||||
<key
|
||||
sequence="M1+#"
|
||||
contextId="org.eclipse.cdt.ui.cEditorScope"
|
||||
commandId="org.eclipse.cdt.ui.edit.open.quick.macro.explorer"
|
||||
schemeId="org.eclipse.ui.defaultAcceleratorConfiguration"/>
|
||||
</extension>
|
||||
<extension
|
||||
point="org.eclipse.ui.commands">
|
||||
|
@ -1638,6 +1648,11 @@
|
|||
description="%toggleMarkOccurrences.description"
|
||||
categoryId="org.eclipse.cdt.ui.category.source"
|
||||
id="org.eclipse.cdt.ui.edit.text.c.toggleMarkOccurrences"/>
|
||||
<command
|
||||
name="%ActionDefinition.showMacroExplorer.name"
|
||||
description="%ActionDefinition.showMacroExplorer.description"
|
||||
categoryId="org.eclipse.cdt.ui.category.source"
|
||||
id="org.eclipse.cdt.ui.edit.open.quick.macro.explorer"/>
|
||||
</extension>
|
||||
<extension
|
||||
id="pdomSearchPage"
|
||||
|
|
|
@ -1182,7 +1182,6 @@ public class CEditor extends TextEditor implements ISelectionChangedListener, IC
|
|||
|
||||
fCEditorErrorTickUpdater = new CEditorErrorTickUpdater(this);
|
||||
|
||||
fMarkOccurrenceAnnotations= store.getBoolean(PreferenceConstants.EDITOR_MARK_OCCURRENCES);
|
||||
fStickyOccurrenceAnnotations= store.getBoolean(PreferenceConstants.EDITOR_STICKY_OCCURRENCES);
|
||||
}
|
||||
|
||||
|
@ -1939,6 +1938,10 @@ public class CEditor extends TextEditor implements ISelectionChangedListener, IC
|
|||
action.setActionDefinitionId(ICEditorActionDefinitionIds.TOGGLE_SOURCE_HEADER);
|
||||
setAction("ToggleSourceHeader", action); //$NON-NLS-1$
|
||||
|
||||
action = new TextOperationAction(CEditorMessages.getResourceBundle(), "OpenMacroExplorer.", this, CSourceViewer.SHOW_MACRO_EXPLORER, true); //$NON-NLS-1$
|
||||
action.setActionDefinitionId(ICEditorActionDefinitionIds.OPEN_QUICK_MACRO_EXPLORER);
|
||||
setAction("OpenMacroExplorer", action); //$NON-NLS-1$*/
|
||||
|
||||
//Assorted action groupings
|
||||
fSelectionSearchGroup = new SelectionSearchGroup(this);
|
||||
fTextSearchGroup= new TextSearchGroup(this);
|
||||
|
@ -1985,6 +1988,7 @@ public class CEditor extends TextEditor implements ISelectionChangedListener, IC
|
|||
|
||||
addAction(menu, IContextMenuConstants.GROUP_OPEN, "OpenOutline"); //$NON-NLS-1$
|
||||
addAction(menu, IContextMenuConstants.GROUP_OPEN, "OpenHierarchy"); //$NON-NLS-1$
|
||||
addAction(menu, IContextMenuConstants.GROUP_OPEN, "OpenMacroExplorer"); //$NON-NLS-1$
|
||||
addAction(menu, IContextMenuConstants.GROUP_OPEN, "ToggleSourceHeader"); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
|
@ -2078,8 +2082,6 @@ public class CEditor extends TextEditor implements ISelectionChangedListener, IC
|
|||
if (sourceViewer instanceof ITextViewerExtension)
|
||||
((ITextViewerExtension) sourceViewer).prependVerifyKeyListener(fBracketInserter);
|
||||
|
||||
if (isMarkingOccurrences())
|
||||
installOccurrencesFinder(false);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2642,6 +2644,12 @@ public class CEditor extends TextEditor implements ISelectionChangedListener, IC
|
|||
((ICReconcilingListener)listeners[i]).reconciled(ast, force, progressMonitor);
|
||||
}
|
||||
|
||||
// delayed installation of mark occurrences
|
||||
if (isMarkingOccurrences() && !fMarkOccurrenceAnnotations)
|
||||
getSite().getShell().getDisplay().asyncExec(new Runnable() {
|
||||
public void run() {
|
||||
installOccurrencesFinder(true);
|
||||
}});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#########################################
|
||||
# Copyright (c) 2005, 2007 IBM Corporation and others.
|
||||
# Copyright (c) 2005, 2008 IBM Corporation 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
|
||||
|
@ -184,3 +184,8 @@ ToggleMarkOccurrencesAction.label= Toggle Mark Occurrences
|
|||
ToggleMarkOccurrencesAction.tooltip= Toggle Mark Occurrences
|
||||
|
||||
CEditor_markOccurrences_job_name= Occurrences Marker
|
||||
|
||||
OpenMacroExplorer.label= Explor &Macro Expansion
|
||||
OpenMacroExplorer.tooltip= Open a quick view for macro expansion exploration
|
||||
OpenMacroExplorer.image=
|
||||
OpenMacroExplorer.description= Opens a quick view for macro expansion exploration
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2006, 2007 QNX Software Systems and others.
|
||||
* Copyright (c) 2006, 2008 QNX Software Systems 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
|
||||
|
@ -52,12 +52,17 @@ public class CSourceViewer extends ProjectionViewer implements IPropertyChangeLi
|
|||
|
||||
/** Show outline operation id. */
|
||||
public static final int SHOW_OUTLINE = 101;
|
||||
/** Show type hierarchy operation id. */
|
||||
public static final int SHOW_HIERARCHY = 102;
|
||||
/** Show macro explorer operation id. */
|
||||
public static final int SHOW_MACRO_EXPLORER = 103;
|
||||
|
||||
/** Presents outline. */
|
||||
private IInformationPresenter fOutlinePresenter;
|
||||
/** Presents type hierarchy. */
|
||||
private IInformationPresenter fHierarchyPresenter;
|
||||
/** Presents macro explorer. */
|
||||
private IInformationPresenter fMacroExplorationPresenter;
|
||||
|
||||
/**
|
||||
* This viewer's foreground color.
|
||||
|
@ -155,6 +160,10 @@ public class CSourceViewer extends ProjectionViewer implements IPropertyChangeLi
|
|||
fHierarchyPresenter= cConfiguration.getHierarchyPresenter(this);
|
||||
if (fHierarchyPresenter != null)
|
||||
fHierarchyPresenter.install(this);
|
||||
fMacroExplorationPresenter= cConfiguration.getMacroExplorationPresenter(this);
|
||||
if (fMacroExplorationPresenter != null) {
|
||||
fMacroExplorationPresenter.install(this);
|
||||
}
|
||||
}
|
||||
if (fPreferenceStore != null) {
|
||||
fPreferenceStore.addPropertyChangeListener(this);
|
||||
|
@ -255,6 +264,10 @@ public class CSourceViewer extends ProjectionViewer implements IPropertyChangeLi
|
|||
if (fHierarchyPresenter != null) {
|
||||
fHierarchyPresenter.uninstall();
|
||||
fHierarchyPresenter= null;
|
||||
}
|
||||
if (fMacroExplorationPresenter != null) {
|
||||
fMacroExplorationPresenter.uninstall();
|
||||
fMacroExplorationPresenter= null;
|
||||
}
|
||||
if (fForegroundColor != null) {
|
||||
fForegroundColor.dispose();
|
||||
|
@ -337,6 +350,8 @@ public class CSourceViewer extends ProjectionViewer implements IPropertyChangeLi
|
|||
case SHOW_HIERARCHY:
|
||||
fHierarchyPresenter.showInformation();
|
||||
return;
|
||||
case SHOW_MACRO_EXPLORER:
|
||||
fMacroExplorationPresenter.showInformation();
|
||||
}
|
||||
super.doOperation(operation);
|
||||
}
|
||||
|
@ -345,12 +360,14 @@ public class CSourceViewer extends ProjectionViewer implements IPropertyChangeLi
|
|||
* @see org.eclipse.jface.text.source.projection.ProjectionViewer#canDoOperation(int)
|
||||
*/
|
||||
public boolean canDoOperation(int operation) {
|
||||
if (operation == SHOW_OUTLINE) {
|
||||
switch (operation) {
|
||||
case SHOW_OUTLINE:
|
||||
return fOutlinePresenter != null;
|
||||
}
|
||||
else if (operation == SHOW_HIERARCHY) {
|
||||
case SHOW_HIERARCHY:
|
||||
return fHierarchyPresenter != null;
|
||||
}
|
||||
case SHOW_MACRO_EXPLORER:
|
||||
return fMacroExplorationPresenter != null;
|
||||
}
|
||||
return super.canDoOperation(operation);
|
||||
}
|
||||
|
||||
|
|
|
@ -193,4 +193,12 @@ public interface ICEditorActionDefinitionIds extends ITextEditorActionDefinition
|
|||
* @since 5.0
|
||||
*/
|
||||
public static final String TOGGLE_MARK_OCCURRENCES= "org.eclipse.cdt.ui.edit.text.c.toggleMarkOccurrences"; //$NON-NLS-1$
|
||||
|
||||
|
||||
/**
|
||||
* Action definition ID of the open macro explorer quick view action
|
||||
* (value <code>"org.eclipse.cdt.ui.edit.open.quick.macro.explorer"</code>).
|
||||
* @since 5.0
|
||||
*/
|
||||
public static final String OPEN_QUICK_MACRO_EXPLORER = "org.eclipse.cdt.ui.edit.open.quick.macro.explorer"; //$NON-NLS-1$
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue