1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-24 17:35:35 +02:00

Patch form Thomas Fletcher to improve on completion.

This commit is contained in:
Alain Magloire 2003-06-24 14:22:14 +00:00
parent aa3f10c491
commit 5248cce011
9 changed files with 784 additions and 176 deletions

View file

@ -1,3 +1,21 @@
2003-06-24 Thomas Fletcher
- Proposals will now include additional help information with them
if it is available (same as JDT). This opens the door for being
able to write a Javadoc/Doxygen parser and integrating live,
context specific, help.
- On function completions a hover is now shown above the function
(same as JDT) with the argument information as it is being filled in.
* src/org/eclipse/cdt/internal/ui/editor/DefaultCEditorTextHover.java
* src/org/eclipse/cdt/internal/ui/text/CCompletionProcessor.java
* src/org/eclipse/cdt/internal/ui/text/CCompletionProposal.java
* src/org/eclipse/cdt/internal/ui/text/CParameterListValidator.java
* src/org/eclipse/cdt/internal/ui/text/CSourceViewerConfiguration.java
* src/org/eclipse/cdt/internal/ui/text/CWordFinder.java
* src/org/eclipse/cdt/ui/IFunctionSummary.java
* src/org/eclipse/cdt/ui/FunctionPrototypeSummary.java
2003-06-23 John Camelon
Updated Factory infrastructure, constructors, etc.
Introduced Preprocessor class for transitive closure calc. client.

View file

@ -60,9 +60,14 @@ public class DefaultCEditorTextHover implements ITextHover
IFunctionSummary fs = CCompletionContributorManager.getDefault().getFunctionInfo(expression);
if(fs != null) {
buffer.append("<b>" + HTMLPrinter.convertToHTMLContent(expression) +
"()</b> - " + HTMLPrinter.convertToHTMLContent(fs.getSummary()) +
"<br><br>" + HTMLPrinter.convertToHTMLContent(fs.getSynopsis()));
buffer.append("<b>");
buffer.append(HTMLPrinter.convertToHTMLContent(fs.getName()));
buffer.append("()</b>");
buffer.append(HTMLPrinter.convertToHTMLContent(fs.getPrototype().getPrototypeString(false)));
if(fs.getDescription() != null) {
buffer.append("<br><br>");
buffer.append(HTMLPrinter.convertToHTMLContent(fs.getDescription()));
}
int i;
for(i = 0; i < buffer.length(); i++) {
if(buffer.charAt(i) == '\\') {

View file

@ -20,6 +20,7 @@ import org.eclipse.cdt.internal.ui.editor.CEditor;
import org.eclipse.cdt.internal.ui.text.template.TemplateEngine;
import org.eclipse.cdt.ui.CElementLabelProvider;
import org.eclipse.cdt.ui.CUIPlugin;
import org.eclipse.cdt.ui.FunctionPrototypeSummary;
import org.eclipse.cdt.ui.IFunctionSummary;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
@ -28,6 +29,7 @@ import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.contentassist.ContextInformation;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
import org.eclipse.jface.text.contentassist.IContextInformation;
@ -46,8 +48,10 @@ public class CCompletionProcessor implements IContentAssistProcessor {
private CEditor fEditor;
private char[] fProposalAutoActivationSet;
private CCompletionProposalComparator fComparator;
private TemplateEngine[] fTemplateEngine;
private IContextInformationValidator fValidator;
private TemplateEngine[] fTemplateEngine;
private boolean fRestrictToMatchingCase;
private boolean fAllowAddIncludes;
@ -56,7 +60,7 @@ public class CCompletionProcessor implements IContentAssistProcessor {
public CCompletionProcessor(IEditorPart editor) {
fEditor = (CEditor) editor;
//Determine if this is a C or a C++ file for the context completion + //This is _totally_ ugly and likely belongs in the main editor class.
String contextNames[] = new String[2];
ArrayList templateList = new ArrayList(2);
@ -123,7 +127,10 @@ public class CCompletionProcessor implements IContentAssistProcessor {
* @see IContentAssistProcessor#getContextInformationValidator()
*/
public IContextInformationValidator getContextInformationValidator() {
return null;
if(fValidator == null) {
fValidator = new CParameterListValidator();
}
return fValidator;
}
/**
@ -133,6 +140,13 @@ public class CCompletionProcessor implements IContentAssistProcessor {
return null;
}
/**
* @see IContentAssistProcessor#computeContextInformation(ITextViewer, int)
*/
public IContextInformation[] computeContextInformation(ITextViewer viewer, int offset) {
return null;
}
/**
* @see IContentAssistProcessor#getCompletionProposalAutoActivationCharacters()
*/
@ -150,13 +164,6 @@ public class CCompletionProcessor implements IContentAssistProcessor {
fProposalAutoActivationSet = activationSet;
}
/**
* @see IContentAssistProcessor#computeContextInformation(ITextViewer, int)
*/
public IContextInformation[] computeContextInformation(ITextViewer viewer, int offset) {
return null;
}
/**
* Tells this processor to restrict is proposals to those
* starting with matching cases.
@ -238,14 +245,7 @@ public class CCompletionProcessor implements IContentAssistProcessor {
* applies to all proposals and not just those of the compilation unit.
*/
order(results);
if ((results.length == 1)
&& (CUIPlugin.getDefault().getPreferenceStore().getBoolean(ContentAssistPreference.AUTOINSERT))) {
results[0].apply(document);
// Trick the content assistant into thinking we have no proposals
return new ICCompletionProposal[0];
} else {
return results;
}
return results;
}
/**
@ -256,102 +256,140 @@ public class CCompletionProcessor implements IContentAssistProcessor {
return proposals;
}
private void addProjectCompletions(IProject project, IRegion region, String frag, ArrayList completions) {
IndexModel model = IndexModel.getDefault();
ITagEntry[] tags = model.query(project, frag + "*", false, false);
if (tags != null && tags.length > 0) {
// We have some matches!
for (int i = 0; i < tags.length; i++) {
String fname = tags[i].getTagName();
int kind = tags[i].getKind();
if (kind == TagFlags.T_FUNCTION || kind == TagFlags.T_PROTOTYPE) {
fname = fname + "()";
}
String proto = fname + " - " + tags[i].getPattern();
//System.out.println("tagmatch " + fname + " proto " + proto + " type" + tags[i].getKind());
if (tags[i].getKind() != TagFlags.T_MEMBER) {
completions.add(new CCompletionProposal(fname, region.getOffset(), region.getLength(),
//fname.length() + 1,
getTagImage(kind), proto.equals("") ? (fname + "()") : proto,
//null,
//null));
3));
}
}
}
}
/**
* Evaluate the actual proposals for C
*/
private ICCompletionProposal[] evalProposals(IDocument document, int pos, int length) {
IRegion region;
boolean isDereference = false;
IRegion region;
String frag = "";
// Move back the pos by one the position is 0-based
if (pos > 0) {
pos--;
}
// First, check if we're on a space or trying to open a struct/union
// TODO: Check to see if we are trying to open for a structure/class, then
// provide that structure's completion instead of the function/variable
// completions. This needs to be properly dealt with so that we can
// offer completion proposals.
if (pos > 1) {
int struct_pos = pos;
try {
// If we're on a space and the previous character is valid text,
// parse the previous word.
if (!Character.isJavaIdentifierPart(document.getChar(pos))) {
pos--;
if (!Character.isJavaIdentifierPart(document.getChar(pos))) {
pos--;
// Comment out the dereference code, only useful once we can
// know variable types to go fish back structure members
//if (document.getChar(offset) == '.') {
// isDereference = true;
// offset--;
//} else if ((document.getChar(offset) == '>') && (document.getChar(offset - 1) == '-')) {
// isDereference = true;
// offset -= 2;
//}
}
//While we aren't on a space, then go back and look for
// . or a -> then determine the structure variable type.
while(document.getChar(struct_pos) == ' ') {
struct_pos--;
}
} catch (BadLocationException e) {
if (document.getChar(struct_pos) == '.') {
isDereference = true;
pos -= struct_pos - 1;
} else if ((document.getChar(struct_pos) == '>') && (document.getChar(struct_pos - 1) == '-')) {
isDereference = true;
pos -= struct_pos - 2;
} else {
isDereference = false;
}
} catch (BadLocationException ex) {
return null;
}
}
// Get the current "word"
// Get the current "word", it might be a variable or another starter
region = CWordFinder.findWord(document, pos);
// If we're currently
try {
if (region != null) {
frag = document.get(region.getOffset(), region.getLength());
frag = frag.trim();
// No word is selected
if (frag.length() == 0) {
return null;
}
} else {
return null;
}
} catch (BadLocationException x) {
// ignore
if(region == null) {
return null; //Bail out on error
}
//@@@ TODO: Implement the structure member completion
if(isDereference) {
return null;
}
// Based on the frag name, build a list of completion proposals
// We look in two places: the content outline and the libs
try {
frag = document.get(region.getOffset(), region.getLength());
frag = frag.trim();
} catch (BadLocationException ex) {
return null; //Bail out on error
}
//If there is no fragment, then see if we are in a function
if(frag.length() == 0) {
IRegion funcregion;
String funcfrag = "";
funcregion = CWordFinder.findFunction(document, pos + 1);
if(funcregion != null) {
try {
funcfrag = document.get(funcregion.getOffset(), funcregion.getLength());
funcfrag = funcfrag.trim();
} catch(Exception ex) {
funcfrag = "";
}
if(funcfrag.length() == 0) {
return null;
} else {
//@@@ Add some marker here to indicate different path!
region = funcregion;
frag = funcfrag;
}
}
}
// Based on the frag name, build a list of completion proposals
ArrayList completions = new ArrayList();
// Look in index manager
addProposalsFromModel(region, frag, completions);
// Loot in the contributed completions
addProposalsFromCompletionContributors(region, frag, completions);
return (ICCompletionProposal[]) completions.toArray(new ICCompletionProposal[0]);
}
private void addProposalsFromCompletionContributors(IRegion region, String frag, ArrayList completions) {
IFunctionSummary[] summary;
summary = CCompletionContributorManager.getDefault().getMatchingFunctions(frag);
if(summary == null) {
return;
}
for (int i = 0; i < summary.length; i++) {
String fname = summary[i].getName() + "()";
String fdesc = summary[i].getDescription();
IFunctionSummary.IFunctionPrototypeSummary fproto = summary[i].getPrototype();
String fargs = fproto.getArguments();
CCompletionProposal proposal;
proposal = new CCompletionProposal(fname,
region.getOffset(),
region.getLength(),
getTagImage(TagFlags.T_FUNCTION),
fproto.getPrototypeString(true),
2);
if(fdesc != null) {
proposal.setAdditionalProposalInfo(fdesc);
}
if(fargs != null && fargs.length() > 0) {
proposal.setContextInformation(new ContextInformation(fname, fargs));
}
completions.add(proposal);
}
}
private void addProposalsFromModel(IRegion region, String frag, ArrayList completions) {
IProject project = null;
IEditorInput input = fEditor.getEditorInput();
if (input instanceof IFileEditorInput) {
project = ((IFileEditorInput) input).getFile().getProject();
// Bail out quickly, if the project was deleted.
if (!project.exists()) {
project = null;
@ -370,26 +408,54 @@ public class CCompletionProcessor implements IContentAssistProcessor {
}
} catch (CoreException e) {
}
}
}
IFunctionSummary[] summary;
private void addProjectCompletions(IProject project, IRegion region, String frag, ArrayList completions) {
IndexModel model = IndexModel.getDefault();
//UserHelpFunctionInfo inf = plugin.getFunctionInfo();
summary = CCompletionContributorManager.getDefault().getMatchingFunctions(frag);
if (summary != null) {
for (int i = 0; i < summary.length; i++) {
String fname = summary[i].getName();
String proto = summary[i].getPrototype();
completions.add(new CCompletionProposal(fname + "()", region.getOffset(), region.getLength(),
//fname.length() + 1,
CPluginImages.get(CPluginImages.IMG_OBJS_FUNCTION), proto.equals("") ? (fname + "()") : proto,
//null,
//null));
2));
ITagEntry[] tags = model.query(project, frag + "*", false, false);
if (tags != null && tags.length > 0) {
for (int i = 0; i < tags.length; i++) {
String fname = tags[i].getTagName();
FunctionPrototypeSummary fproto = null;
int kind = tags[i].getKind();
if (kind == TagFlags.T_FUNCTION || kind == TagFlags.T_PROTOTYPE) {
fname = fname + "()";
}
if(tags[i].getPattern() != null) {
try {
fproto = new FunctionPrototypeSummary(tags[i].getPattern());
} catch(Exception ex) {
fproto = null;
}
}
if(fproto == null) {
fproto = new FunctionPrototypeSummary(fname);
}
//System.out.println("tagmatch " + fname + " proto " + proto + " type" + tags[i].getKind());
if (kind != TagFlags.T_MEMBER) {
CCompletionProposal proposal;
proposal = new CCompletionProposal(fname,
region.getOffset(),
region.getLength(),
getTagImage(kind),
fproto.getPrototypeString(true),
3);
completions.add(proposal);
//No summary information available yet
String fargs = fproto.getArguments();
if(fargs != null && fargs.length() > 0) {
proposal.setContextInformation(new ContextInformation(fname, fargs));
}
}
}
}
return (ICCompletionProposal[]) completions.toArray(new ICCompletionProposal[0]);
}
private Image getTagImage(int kind) {

View file

@ -7,22 +7,22 @@ package org.eclipse.cdt.internal.ui.text;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.contentassist.ICompletionProposalExtension;
import org.eclipse.jface.text.contentassist.IContextInformation;
import org.eclipse.jface.util.Assert;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
public class CCompletionProposal implements ICCompletionProposal {
public class CCompletionProposal implements ICCompletionProposal, ICompletionProposalExtension {
private String fDisplayString;
private String fReplacementString;
private String fAdditionalInfoString;
private int fReplacementOffset;
private int fReplacementLength;
private int fCursorPosition;
private Image fImage;
private IContextInformation fContextInformation;
private int fContextInformationPosition;
//private ProposalInfo fProposalInfo;
//private IImportDeclaration fImportDeclaration;
private char[] fTriggerCharacters;
@ -50,13 +50,20 @@ public class CCompletionProposal implements ICCompletionProposal {
fDisplayString= displayString != null ? displayString : replacementString;
fRelevance= relevance;
fCursorPosition= replacementString.length();
//@@@ Is this the best way to do this, likely it isn't
if(replacementString.indexOf("()") == -1) { //Not replacing with a function
fCursorPosition = replacementString.length();
} else if(displayString.indexOf("()") == -1) { //Assume that there are arguments between ()
fCursorPosition = replacementString.length() - 1;
} else {
fCursorPosition = replacementString.length();
}
fAdditionalInfoString = null;
fContextInformation= null;
fContextInformationPosition= -1;
//fIncludeDeclaration= null;
fTriggerCharacters= null;
//fProposalInfo= null;
}
/**
@ -85,14 +92,6 @@ public class CCompletionProposal implements ICCompletionProposal {
fTriggerCharacters= triggerCharacters;
}
/**
* Sets the proposal info.
* @param additionalProposalInfo The additional information associated with this proposal or <code>null</code>
*
public void setProposalInfo(ProposalInfo proposalInfo) {
fProposalInfo= proposalInfo;
}*/
/**
* Sets the cursor position relative to the insertion offset. By default this is the length of the completion string
* (Cursor positioned after the completion)
@ -146,22 +145,49 @@ public class CCompletionProposal implements ICCompletionProposal {
}
} */
}
/*
* @see ICompletionProposal#apply
*/
public void apply(IDocument document) {
apply(document, (char) 0, fReplacementOffset + fReplacementLength);
}
/*
* In this case we need to apply the completion proposal intelligently.
* This means that if we are applying it to a function, we don't wipe
* out the internal arguments, and if the proposal is a function, and it
* already is bracketed, then don't put those brackets in.
*
* @see ICompletionProposalExtension#apply(IDocument, char, int)
*/
public void apply(IDocument document, char trigger, int offset) {
int functionBracketIndex;
boolean isBeforeBracket;
String replacementStringCopy = fReplacementString;
//If just providing context information, then don't move the cursor
if(offset != (fReplacementOffset + fReplacementLength)) {
fCursorPosition = offset - fReplacementOffset;
}
try {
functionBracketIndex = fReplacementString.indexOf("()");
isBeforeBracket = document.getChar(fReplacementOffset + fReplacementLength) == '(';
// patch replacement length
int delta= offset - (fReplacementOffset + fReplacementLength);
if (delta > 0)
fReplacementLength += delta;
//Strip the brackets off the function if inserting right before brackets
if(functionBracketIndex != -1 && isBeforeBracket) {
replacementStringCopy = fReplacementString.substring(0, functionBracketIndex);
}
} catch(Exception ex) {
/* Ignore */
}
try {
if (trigger == (char) 0) {
replace(document, fReplacementOffset, fReplacementLength, fReplacementString);
replace(document, fReplacementOffset, fReplacementLength, replacementStringCopy);
} else {
StringBuffer buffer= new StringBuffer(fReplacementString);
StringBuffer buffer= new StringBuffer(replacementStringCopy);
// fix for PR #5533. Assumes that no eating takes place.
if ((fCursorPosition > 0 && fCursorPosition <= buffer.length() && buffer.charAt(fCursorPosition - 1) != trigger)) {
@ -172,6 +198,12 @@ public class CCompletionProposal implements ICCompletionProposal {
replace(document, fReplacementOffset, fReplacementLength, buffer.toString());
}
/*
* The replacement length is used to calculate the new cursor position,
* so after we update the includes adjust the replacement offset.
* NOTE: This won't work if the include is added after the offset,
* such as might be the case with #include completions.
*/
int oldLen= document.getLength();
applyIncludes(document);
fReplacementOffset += document.getLength() - oldLen;
@ -186,13 +218,6 @@ public class CCompletionProposal implements ICCompletionProposal {
if (!document.get(offset, length).equals(string))
document.replace(offset, length, string);
}
/*
* @see ICompletionProposal#apply
*/
public void apply(IDocument document) {
apply(document, (char) 0, fReplacementOffset + fReplacementLength);
}
/*
* @see ICompletionProposal#getSelection
@ -222,14 +247,20 @@ public class CCompletionProposal implements ICCompletionProposal {
return fDisplayString;
}
/**
* Set the additional information which will be shown when this
* proposal is selected in the popup list.
* @param infoString
*/
public void setAdditionalProposalInfo(String infoString) {
fAdditionalInfoString = infoString;
}
/*
* @see ICompletionProposal#getAdditionalProposalInfo()
*/
public String getAdditionalProposalInfo() {
//if (fProposalInfo != null) {
// return fProposalInfo.getInfo();
//}
return null;
return fAdditionalInfoString;
}
/*
@ -245,6 +276,27 @@ public class CCompletionProposal implements ICCompletionProposal {
public int getContextInformationPosition() {
return fReplacementOffset + fContextInformationPosition;
}
/*
* @see ICompletionProposalExtension#isValidFor(IDocument, int)
*/
public boolean isValidFor(IDocument document, int offset) {
if (offset < fReplacementOffset)
return false;
int replacementLength= fReplacementString == null ? 0 : fReplacementString.length();
if (offset >= fReplacementOffset + replacementLength)
return false;
try {
int length= offset - fReplacementOffset;
String start= document.get(fReplacementOffset, length);
return fReplacementString.substring(0, length).equalsIgnoreCase(start);
} catch (BadLocationException x) {
}
return false;
}
/**
* Gets the replacement offset.
@ -303,28 +355,6 @@ public class CCompletionProposal implements ICCompletionProposal {
public void setImage(Image image) {
fImage= image;
}
/*
* @see ICompletionProposalExtension#isValidFor(IDocument, int)
*/
public boolean isValidFor(IDocument document, int offset) {
if (offset < fReplacementOffset)
return false;
int replacementLength= fReplacementString == null ? 0 : fReplacementString.length();
if (offset >= fReplacementOffset + replacementLength)
return false;
try {
int length= offset - fReplacementOffset;
String start= document.get(fReplacementOffset, length);
return fReplacementString.substring(0, length).equalsIgnoreCase(start);
} catch (BadLocationException x) {
}
return false;
}
/**
* Gets the proposal's relevance.

View file

@ -0,0 +1,216 @@
package org.eclipse.cdt.internal.ui.text;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.jface.text.Assert;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.TextPresentation;
import org.eclipse.jface.text.contentassist.IContextInformation;
import org.eclipse.jface.text.contentassist.IContextInformationPresenter;
import org.eclipse.jface.text.contentassist.IContextInformationValidator;
/**
* This class provides the function parameter parsing for the C/C++ Editor hover
* It is based heavily on the Java class JavaParameterListValidator
*
* @author thomasf
*
*/
public class CParameterListValidator implements IContextInformationValidator, IContextInformationPresenter {
private int fPosition;
private ITextViewer fViewer;
private IContextInformation fInformation;
private int fCurrentParameter;
public CParameterListValidator() {
}
/**
* @see IContextInformationValidator#install(IContextInformation, ITextViewer, int)
* @see IContextInformationPresenter#install(IContextInformation, ITextViewer, int)
*/
public void install(IContextInformation info, ITextViewer viewer, int documentPosition) {
fPosition= documentPosition;
fViewer= viewer;
fInformation= info;
fCurrentParameter= -1;
}
private int getCommentEnd(IDocument d, int pos, int end) throws BadLocationException {
while (pos < end) {
char curr= d.getChar(pos);
pos++;
if (curr == '*') {
if (pos < end && d.getChar(pos) == '/') {
return pos + 1;
}
}
}
return end;
}
private int getStringEnd(IDocument d, int pos, int end, char ch) throws BadLocationException {
while (pos < end) {
char curr= d.getChar(pos);
pos++;
if (curr == '\\') {
// ignore escaped characters
pos++;
} else if (curr == ch) {
return pos;
}
}
return end;
}
private int getCharCount(IDocument document, int start, int end,
char increment, char decrement, boolean considerNesting) throws BadLocationException {
Assert.isTrue((increment != 0 || decrement != 0) && increment != decrement);
int nestingLevel= 0;
int charCount= 0;
while (start < end) {
char curr= document.getChar(start++);
switch (curr) {
case '/':
if (start < end) {
char next= document.getChar(start);
if (next == '*') {
// a comment starts, advance to the comment end
start= getCommentEnd(document, start + 1, end);
} else if (next == '/') {
// '//'-comment: nothing to do anymore on this line
start= end;
}
}
break;
case '*':
if (start < end) {
char next= document.getChar(start);
if (next == '/') {
// we have been in a comment: forget what we read before
charCount= 0;
++ start;
}
}
break;
case '"':
case '\'':
start= getStringEnd(document, start, end, curr);
break;
default:
if (considerNesting) {
if ('(' == curr)
++ nestingLevel;
else if (')' == curr)
-- nestingLevel;
if (nestingLevel != 0)
break;
}
if (increment != 0) {
if (curr == increment)
++ charCount;
}
if (decrement != 0) {
if (curr == decrement)
-- charCount;
}
}
}
return charCount;
}
/**
* @see IContextInformationValidator#isContextInformationValid(int)
*/
public boolean isContextInformationValid(int position) {
try {
if (position < fPosition)
return false;
IDocument document= fViewer.getDocument();
IRegion line= document.getLineInformationOfOffset(fPosition);
if (position > line.getOffset() + line.getLength())
return false;
return (getCharCount(document, fPosition, position, '(', ')', false) >= 0);
} catch (BadLocationException x) {
return false;
}
}
/**
* @see IContextInformationPresenter#updatePresentation(int, TextPresentation)
*/
public boolean updatePresentation(int position, TextPresentation presentation) {
int currentParameter= -1;
try {
currentParameter= getCharCount(fViewer.getDocument(), fPosition, position, ',', (char) 0, true);
} catch (BadLocationException x) {
return false;
}
if (fCurrentParameter != -1) {
if (currentParameter == fCurrentParameter)
return false;
}
presentation.clear();
fCurrentParameter= currentParameter;
String s= fInformation.getInformationDisplayString().trim();
int start= 0;
int occurrences= 0;
while (occurrences < fCurrentParameter) {
int found= s.indexOf(',', start);
if (found == -1)
break;
start= found + 1;
++ occurrences;
}
if (occurrences < fCurrentParameter) {
presentation.addStyleRange(new StyleRange(0, s.length(), null, null, SWT.NORMAL));
return true;
}
if (start == -1)
start= 0;
int end= s.indexOf(',', start);
if (end == -1)
end= s.length();
if (start > 0)
presentation.addStyleRange(new StyleRange(0, start, null, null, SWT.NORMAL));
if (end > start)
presentation.addStyleRange(new StyleRange(start, end - start, null, null, SWT.BOLD));
if (end < s.length())
presentation.addStyleRange(new StyleRange(end, s.length() - end, null, null, SWT.NORMAL));
return true;
}
}

View file

@ -26,6 +26,7 @@ import org.eclipse.jface.text.IInformationControlCreator;
import org.eclipse.jface.text.ITextDoubleClickStrategy;
import org.eclipse.jface.text.ITextHover;
import org.eclipse.jface.text.contentassist.ContentAssistant;
import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
import org.eclipse.jface.text.contentassist.IContentAssistant;
import org.eclipse.jface.text.formatter.ContentFormatter;
import org.eclipse.jface.text.formatter.IContentFormatter;
@ -158,7 +159,6 @@ public class CSourceViewerConfiguration extends SourceViewerConfiguration {
reconciler.setDamager(dr, CPartitionScanner.C_MULTILINE_COMMENT);
reconciler.setRepairer(dr, CPartitionScanner.C_MULTILINE_COMMENT);
return reconciler;
}
@ -167,15 +167,30 @@ public class CSourceViewerConfiguration extends SourceViewerConfiguration {
* @see SourceViewerConfiguration#getContentAssistant(ISourceViewer)
*/
public IContentAssistant getContentAssistant(ISourceViewer sourceViewer) {
if(getEditor() == null) {
return null;
}
ContentAssistant assistant = new ContentAssistant();
// IFile file = (sourceViewer).
assistant.setContentAssistProcessor(new CCompletionProcessor(fEditor), IDocument.DEFAULT_CONTENT_TYPE);
IContentAssistProcessor processor = new CCompletionProcessor(getEditor());
assistant.setContentAssistProcessor(processor, IDocument.DEFAULT_CONTENT_TYPE);
//Will this work as a replacement for the configuration lines below?
//ContentAssistPreference.configure(assistant, getPreferenceStore());
assistant.enableAutoInsert(CUIPlugin.getDefault().getPreferenceStore().getBoolean(ContentAssistPreference.AUTOINSERT));
assistant.enableAutoActivation(true);
assistant.setAutoActivationDelay(500);
assistant.setProposalPopupOrientation(IContentAssistant.PROPOSAL_OVERLAY);
assistant.setContextInformationPopupOrientation(ContentAssistant.CONTEXT_INFO_ABOVE);
assistant.setInformationControlCreator(getInformationControlCreator(sourceViewer));
return assistant;
}
/**
* @see SourceViewerConfiguration#getReconciler(ISourceViewer)
*/
@ -367,7 +382,7 @@ public class CSourceViewerConfiguration extends SourceViewerConfiguration {
public IInformationControlCreator getInformationControlCreator(ISourceViewer sourceViewer, final boolean cutDown) {
return new IInformationControlCreator() {
public IInformationControl createInformationControl(Shell parent) {
int style= cutDown ? SWT.NONE : (SWT.V_SCROLL | SWT.H_SCROLL);
int style = cutDown ? SWT.NONE : (SWT.V_SCROLL | SWT.H_SCROLL);
return new DefaultInformationControl(parent, style, new HTMLTextPresenter(cutDown));
// return new HoverBrowserControl(parent);
}

View file

@ -10,9 +10,31 @@ import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.Region;
/**
* This is a helper class for the text editor to be able to determine,
* given a particular offset in a document, various candidates segments
* for things like context help, proposals and hovering.
*/
public class CWordFinder
{
/**
* This method determines for a given offset into a given document
* what the region is which defines the current word. A word is
* defined as the set of non "C" identifiers. So assuming that !
* indicated the current cursor postion:
* !afunction(int a, int b) --> word = length 0
* afunc!tion(int a, int b) --> word = afunction
* afunction!(int a, int b) --> word = afunction
* afunction(!int a, int b) --> word = length 0
* afunction(int a,! int b) --> word = length 0
* afunction(!) --> word = length 0
* @param document The document to be examined
* @param offset The offset into the document where a word should
* be idendified.
* @return The region defining the current word, which may be a
* region of length 0 if the offset is not in a word, or null if
* there is an error accessing the docment data.
*/
public static IRegion findWord( IDocument document, int offset )
{
int start = -1;
@ -63,6 +85,121 @@ public class CWordFinder
return null;
}
/**
* This method will determine the region for the name of the function
* within which the current offset is contained.
* @param document The document to be examined
* @param offset The offset into the document where a word should
* be idendified.
* @return The region defining the current word, which may be a
* region of length 0 if the offset is not in a function, or null if
* there is an error accessing the docment data.
*/
public static IRegion findFunction( IDocument document, int offset )
{
int leftbracket = -1;
int leftbracketcount = 0;
int rightbracket = -1;
int rightbracketcount = 0;
int functionstart = -1;
int functionend = -1;
try
{
int length = document.getLength();
int pos;
char c;
//Find most relevant right bracket from our position
pos = offset;
rightbracketcount = leftbracketcount = 0;
while(pos < length) {
c = document.getChar( pos );
if( c == ')') {
rightbracketcount++;
if(rightbracketcount >= leftbracketcount) {
rightbracket = pos;
break;
}
}
if(c == '(') {
leftbracketcount++;
}
if(c == ';') {
break;
}
pos++;
}
if ( rightbracket == -1 ) {
return new Region(offset, 0);
}
//Now backtrack our way from the rightbracket to the left
pos = rightbracket;
rightbracketcount = leftbracketcount = 0;
while(pos >= 0) {
c = document.getChar( pos );
if( c == ')') {
rightbracketcount++;
}
if(c == '(') {
leftbracketcount++;
if(leftbracketcount >= rightbracketcount) {
leftbracket = pos;
break;
}
}
if(c == ';') {
break;
}
pos--;
}
if ( leftbracket == -1 ) {
return new Region(offset, 0);
}
//Now work our way to the function name
pos = leftbracket - 1;
while(pos >= 0) {
c = document.getChar( pos );
if(functionend == -1 && c == ' ' ) {
continue;
}
if(!Character.isJavaIdentifierPart(c)) {
break;
}
functionstart = pos;
if(functionend == -1) {
functionend = pos;
}
pos--;
}
} catch( BadLocationException x ) {
/* Ignore */
}
if (functionstart > -1 && functionend > -1) {
return new Region(functionstart, functionend - functionstart + 1);
}
return null;
}
}

View file

@ -0,0 +1,69 @@
package org.eclipse.cdt.ui;
/**
* This class is a helper class which takes care of implementing some of the
* function prototype parsing and stripping.
*/
public class FunctionPrototypeSummary implements IFunctionSummary.IFunctionPrototypeSummary {
String fname;
String freturn;
String farguments;
/**
* Creates a prototype which matches the format
* returntype function(arguments)
* @param properProto
*/
public FunctionPrototypeSummary(String proto) {
int leftbracket = proto.indexOf('(');
int rightbracket = proto.lastIndexOf(')');
farguments = proto.substring(leftbracket + 1, rightbracket);
int nameend = leftbracket - 1;
while(proto.charAt(nameend) == ' ') {
nameend--;
}
int namestart = nameend;
while(namestart > 0 && proto.charAt(namestart) != ' ') {
namestart--;
}
fname = proto.substring(namestart, nameend + 1).trim();
if(namestart == 0) {
freturn = "void";
} else {
freturn = proto.substring(0, namestart).trim();
}
}
public String getName() {
return fname;
}
public String getReturnType() {
return freturn;
}
public String getArguments() {
return farguments;
}
public String getPrototypeString(boolean namefirst) {
StringBuffer buffer = new StringBuffer();
if(!namefirst) {
buffer.append(getArguments());
buffer.append(" ");
}
buffer.append(getName());
buffer.append("(");
if(getArguments() != null) {
buffer.append(getArguments());
}
buffer.append(")");
if(namefirst) {
buffer.append(" ");
buffer.append(getReturnType());
}
return buffer.toString();
}
}

View file

@ -7,28 +7,80 @@ package org.eclipse.cdt.ui;
public interface IFunctionSummary {
public interface IFunctionPrototypeSummary {
/**
* Get the name of the function. This should be the
* same as for IFunctionSummary.
* ie "int main(int argc, char **argv)" --> "main"
* @return The name of the function without any additional
* information.
*/
public String getName();
/**
* Get the return type of the function.
* ie "int main(int argc, char **argv)" --> "int"
* @return A string containing the return type of the
* function.
*/
public String getReturnType();
/**
* Get the arguments of the function.
* ie "int main(int argc, char **argv)" --> "int argc, char **argv"
* @return A string containing the arguments of the
* function, or null if the function has no arguments.
*/
public String getArguments();
/**
* Get a nice user defined string. The format of
* which depends on the variable namefirst
* namefirst == true: main(int argc, char **argv) int
* namefirst == false: int main(int argc, char **argv);
* @return
*/
public String getPrototypeString(boolean namefirst);
}
/**
* Get the name of the function
* Gets the name of the function. This is the simple
* name without any additional return or argument information.
* The function "int main(int argc, char **argv)" would
* return "main"
* @return The name of the function without any additional
* information
*/
public String getName();
/**
* Get the full namespace qualifier for this function
* (generally C++ only)
* @return The string of the fully qualified namespace for
* this function, or null if the namespace is not known.
*/
public String getNamespace();
/**
* Gets the description of the function. This string can be
* either text or HTML coded and is displayed as part of the
* hover help and as the context proposal information.
* @return A description for this function, or null if no
* description is available.
*/
public String getDescription();
/**
* Get the function summary
* Gets the prototype description for this function.
* @return The IFunctionPrototypeSummary describing the
* prototype for this function
*/
public String getSummary();
/**
* Get the function prototype
*/
public String getPrototype();
/**
* Get the function synopsis
*/
public String getSynopsis();
public IFunctionPrototypeSummary getPrototype();
/**
* Get headers required by this function
* @return A list of IRequiredInclude definitions, or null if no
* include definitions are available.
*/
public IRequiredInclude[] getIncludes();
}