mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-29 19:45:01 +02:00
113568: [Content Assist] proposals for include directives
This commit is contained in:
parent
2d526547f2
commit
bfd296013f
8 changed files with 508 additions and 41 deletions
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2004, 2007 IBM Corporation and others.
|
||||
* Copyright (c) 2004, 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
|
||||
|
@ -15,14 +15,13 @@ package org.eclipse.cdt.ui.tests.text.contentassist2;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.core.resources.IFile;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.runtime.NullProgressMonitor;
|
||||
import org.eclipse.jface.text.IDocument;
|
||||
import org.eclipse.jface.text.TextUtilities;
|
||||
import org.eclipse.jface.text.contentassist.ContentAssistant;
|
||||
import org.eclipse.jface.text.contentassist.ICompletionProposal;
|
||||
import org.eclipse.jface.text.contentassist.IContextInformation;
|
||||
|
@ -34,17 +33,16 @@ import org.eclipse.ui.texteditor.ITextEditor;
|
|||
import org.eclipse.cdt.core.CCorePlugin;
|
||||
import org.eclipse.cdt.core.dom.IPDOMManager;
|
||||
import org.eclipse.cdt.core.model.ICProject;
|
||||
import org.eclipse.cdt.core.parser.KeywordSetKey;
|
||||
import org.eclipse.cdt.core.parser.ParserFactory;
|
||||
import org.eclipse.cdt.core.parser.ParserLanguage;
|
||||
import org.eclipse.cdt.core.testplugin.CProjectHelper;
|
||||
import org.eclipse.cdt.ui.testplugin.CTestPlugin;
|
||||
import org.eclipse.cdt.ui.tests.BaseUITestCase;
|
||||
import org.eclipse.cdt.ui.tests.text.EditorTestHelper;
|
||||
import org.eclipse.cdt.ui.text.ICCompletionProposal;
|
||||
import org.eclipse.cdt.ui.text.ICPartitions;
|
||||
|
||||
import org.eclipse.cdt.internal.ui.text.contentassist.CCompletionProposal;
|
||||
import org.eclipse.cdt.internal.ui.text.contentassist.CContentAssistProcessor;
|
||||
import org.eclipse.cdt.internal.ui.text.contentassist.RelevanceConstants;
|
||||
|
||||
public abstract class AbstractContentAssistTest extends BaseUITestCase {
|
||||
|
||||
|
@ -57,14 +55,6 @@ public abstract class AbstractContentAssistTest extends BaseUITestCase {
|
|||
protected ITextEditor fEditor;
|
||||
private boolean fIsCpp;
|
||||
|
||||
private final static Set fgAllKeywords= new HashSet();
|
||||
|
||||
static {
|
||||
fgAllKeywords.addAll(ParserFactory.getKeywordSet(KeywordSetKey.KEYWORDS, ParserLanguage.C));
|
||||
fgAllKeywords.addAll(ParserFactory.getKeywordSet(KeywordSetKey.TYPES, ParserLanguage.C));
|
||||
fgAllKeywords.addAll(ParserFactory.getKeywordSet(KeywordSetKey.KEYWORDS, ParserLanguage.CPP));
|
||||
fgAllKeywords.addAll(ParserFactory.getKeywordSet(KeywordSetKey.TYPES, ParserLanguage.CPP));
|
||||
}
|
||||
public AbstractContentAssistTest(String name, boolean isCpp) {
|
||||
super(name);
|
||||
fIsCpp= isCpp;
|
||||
|
@ -111,7 +101,8 @@ public abstract class AbstractContentAssistTest extends BaseUITestCase {
|
|||
|
||||
//Call the CContentAssistProcessor
|
||||
ISourceViewer sourceViewer= EditorTestHelper.getSourceViewer((AbstractTextEditor)fEditor);
|
||||
String contentType = sourceViewer.getDocument().getContentType(offset);
|
||||
String contentType= TextUtilities.getContentType(sourceViewer.getDocument(), ICPartitions.C_PARTITIONING, offset, true);
|
||||
boolean isCode= IDocument.DEFAULT_CONTENT_TYPE.equals(contentType);
|
||||
ContentAssistant assistant = new ContentAssistant();
|
||||
CContentAssistProcessor processor = new CContentAssistProcessor(fEditor, assistant, contentType);
|
||||
long startTime= System.currentTimeMillis();
|
||||
|
@ -121,7 +112,7 @@ public abstract class AbstractContentAssistTest extends BaseUITestCase {
|
|||
long endTime= System.currentTimeMillis();
|
||||
assertTrue(results != null);
|
||||
|
||||
results= filterResults(results);
|
||||
results= filterResults(results, isCode);
|
||||
String[] resultStrings= toStringArray(results, compareType);
|
||||
Arrays.sort(expected);
|
||||
Arrays.sort(resultStrings);
|
||||
|
@ -167,22 +158,31 @@ public abstract class AbstractContentAssistTest extends BaseUITestCase {
|
|||
/**
|
||||
* Filter out template and keyword proposals.
|
||||
* @param results
|
||||
* @param isCodeCompletion completion is in code, not preprocessor, etc.
|
||||
* @return filtered proposals
|
||||
*/
|
||||
private Object[] filterResults(Object[] results) {
|
||||
List filtered= new ArrayList();
|
||||
private Object[] filterResults(Object[] results, boolean isCodeCompletion) {
|
||||
List<Object> filtered= new ArrayList<Object>();
|
||||
for (int i = 0; i < results.length; i++) {
|
||||
Object result = results[i];
|
||||
if (result instanceof TemplateProposal) {
|
||||
continue;
|
||||
}
|
||||
if (result instanceof ICCompletionProposal) {
|
||||
// check for keywords proposal
|
||||
if (fgAllKeywords.contains(((ICCompletionProposal)result).getDisplayString())) {
|
||||
continue;
|
||||
if (isCodeCompletion) {
|
||||
// check for keywords proposal
|
||||
int relevance = ((ICCompletionProposal)result).getRelevance();
|
||||
if (relevance >= RelevanceConstants.CASE_MATCH_RELEVANCE) {
|
||||
relevance -= RelevanceConstants.CASE_MATCH_RELEVANCE;
|
||||
}
|
||||
if (relevance <= RelevanceConstants.KEYWORD_TYPE_RELEVANCE) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
filtered.add(result);
|
||||
} else if (result instanceof IContextInformation) {
|
||||
filtered.add(result);
|
||||
}
|
||||
filtered.add(result);
|
||||
}
|
||||
return filtered.toArray();
|
||||
}
|
||||
|
@ -191,7 +191,7 @@ public abstract class AbstractContentAssistTest extends BaseUITestCase {
|
|||
String[] strings= new String[results.length];
|
||||
for(int i=0; i< results.length; i++){
|
||||
Object result = results[i];
|
||||
if (result instanceof ICompletionProposal) {
|
||||
if (result instanceof CCompletionProposal) {
|
||||
if (compareType == COMPARE_ID_STRINGS) {
|
||||
strings[i]= ((CCompletionProposal)result).getIdString();
|
||||
} else if (compareType == COMPARE_DISP_STRINGS) {
|
||||
|
@ -199,8 +199,20 @@ public abstract class AbstractContentAssistTest extends BaseUITestCase {
|
|||
} else {
|
||||
strings[i]= ((CCompletionProposal)result).getReplacementString();
|
||||
}
|
||||
} else {
|
||||
} else if (result instanceof ICCompletionProposal) {
|
||||
if (compareType == COMPARE_ID_STRINGS) {
|
||||
strings[i]= ((ICCompletionProposal)result).getIdString();
|
||||
} else if (compareType == COMPARE_DISP_STRINGS) {
|
||||
strings[i]= ((ICCompletionProposal)result).getDisplayString();
|
||||
} else {
|
||||
strings[i]= ((ICCompletionProposal)result).getDisplayString();
|
||||
}
|
||||
} else if (result instanceof ICompletionProposal) {
|
||||
strings[i]= ((ICompletionProposal)result).getDisplayString();
|
||||
} else if (result instanceof IContextInformation) {
|
||||
strings[i]= ((IContextInformation)result).getContextDisplayString();
|
||||
} else {
|
||||
strings[i]= result.toString();
|
||||
}
|
||||
}
|
||||
return strings;
|
||||
|
|
|
@ -13,6 +13,11 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.cdt.ui.tests.text.contentassist2;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import junit.framework.Test;
|
||||
|
||||
import org.eclipse.core.resources.IFile;
|
||||
|
@ -20,6 +25,7 @@ import org.eclipse.core.resources.IProject;
|
|||
import org.eclipse.jface.text.IDocument;
|
||||
|
||||
import org.eclipse.cdt.core.CCorePlugin;
|
||||
import org.eclipse.cdt.core.testplugin.TestScannerProvider;
|
||||
import org.eclipse.cdt.core.testplugin.util.BaseTestCase;
|
||||
import org.eclipse.cdt.core.testplugin.util.TestSourceReader;
|
||||
|
||||
|
@ -951,4 +957,75 @@ public class CompletionTests extends AbstractContentAssistTest {
|
|||
};
|
||||
assertCompletionResults(fCursorOffset, expected, AbstractContentAssistTest.COMPARE_REP_STRINGS);
|
||||
}
|
||||
|
||||
//#include "/*cursor*/
|
||||
public void testInclusionProposals_bug113568() throws Exception {
|
||||
File tempRoot= new File(System.getProperty("java.io.tmpdir"));
|
||||
File tempDir= new File(tempRoot, "cdttest_113568");
|
||||
tempDir.mkdir();
|
||||
try {
|
||||
createIncludeFiles(tempDir, new String[] {
|
||||
"h1/inc1.h",
|
||||
"h1/sub1/inc11.h",
|
||||
"h2/inc2.h"
|
||||
});
|
||||
String[] expected= {
|
||||
"\"inc1.h\"",
|
||||
"\"sub1/\"",
|
||||
"\"inc2.h\""
|
||||
};
|
||||
assertCompletionResults(fCursorOffset, expected, AbstractContentAssistTest.COMPARE_REP_STRINGS);
|
||||
|
||||
getDocument().replace(fCursorOffset++, 0, "i");
|
||||
expected= new String[] {
|
||||
"\"inc1.h\"",
|
||||
"\"inc2.h\""
|
||||
};
|
||||
assertCompletionResults(fCursorOffset, expected, AbstractContentAssistTest.COMPARE_REP_STRINGS);
|
||||
|
||||
getDocument().replace(fCursorOffset, 0, "\"");
|
||||
expected= new String[] {
|
||||
"\"inc1.h",
|
||||
"\"inc2.h"
|
||||
};
|
||||
assertCompletionResults(fCursorOffset, expected, AbstractContentAssistTest.COMPARE_REP_STRINGS);
|
||||
|
||||
getDocument().replace(fCursorOffset-1, 1, "sub1/");
|
||||
expected= new String[] {
|
||||
"\"sub1/inc11.h"
|
||||
};
|
||||
assertCompletionResults(fCursorOffset+=4, expected, AbstractContentAssistTest.COMPARE_REP_STRINGS);
|
||||
} finally {
|
||||
deleteDir(tempDir);
|
||||
}
|
||||
}
|
||||
|
||||
public static void deleteDir(File dir) {
|
||||
File[] files = dir.listFiles();
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
if (files[i].isDirectory()) {
|
||||
deleteDir(files[i]);
|
||||
} else {
|
||||
files[i].delete();
|
||||
}
|
||||
}
|
||||
dir.delete();
|
||||
}
|
||||
|
||||
private static void createIncludeFiles(File dir, String[] files) throws IOException {
|
||||
Set<String> includeDirs= new HashSet<String>();
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
File file = new File(dir, files[i]);
|
||||
final File parentFile= file.getParentFile();
|
||||
if (parentFile.getName().startsWith("sub")) {
|
||||
if (!parentFile.exists()) {
|
||||
parentFile.mkdirs();
|
||||
}
|
||||
} else if (includeDirs.add(parentFile.getAbsolutePath())) {
|
||||
parentFile.mkdirs();
|
||||
}
|
||||
file.createNewFile();
|
||||
}
|
||||
TestScannerProvider.sIncludes= (String[]) includeDirs.toArray(new String[includeDirs.size()]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2184,6 +2184,15 @@
|
|||
<partition type="__c_preprocessor"/>
|
||||
</completionProposalComputer>
|
||||
</extension>
|
||||
<extension
|
||||
id="InclusionProposalComputer"
|
||||
point="org.eclipse.cdt.ui.completionProposalComputer">
|
||||
<completionProposalComputer
|
||||
categoryId="org.eclipse.cdt.ui.parserProposalCategory"
|
||||
class="org.eclipse.cdt.internal.ui.text.contentassist.InclusionProposalComputer">
|
||||
<partition type="__c_preprocessor"/>
|
||||
</completionProposalComputer>
|
||||
</extension>
|
||||
|
||||
<extension
|
||||
id="KeywordCompletionProposalComputer"
|
||||
|
|
|
@ -169,7 +169,7 @@ public class CCompletionProposal implements ICCompletionProposal, ICompletionPro
|
|||
Assert.isTrue(cursorPosition >= 0);
|
||||
fCursorPosition= cursorPosition;
|
||||
fContextInformationPosition= (fContextInformation != null ? fCursorPosition : -1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @see ICompletionProposalExtension#apply(IDocument, char, int)
|
||||
|
@ -478,11 +478,7 @@ public class CCompletionProposal implements ICCompletionProposal, ICompletionPro
|
|||
if (offset < fReplacementOffset)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* See http://dev.eclipse.org/bugs/show_bug.cgi?id=17667
|
||||
String word= fReplacementString;
|
||||
*/
|
||||
boolean validated= startsWith(document, offset, fDisplayString);
|
||||
boolean validated= startsWith(document, offset, fReplacementString);
|
||||
|
||||
if (validated && event != null) {
|
||||
// adapt replacement range to document change
|
||||
|
@ -515,7 +511,7 @@ public class CCompletionProposal implements ICCompletionProposal, ICompletionPro
|
|||
*/
|
||||
protected boolean startsWith(IDocument document, int offset, String word) {
|
||||
int wordLength= word == null ? 0 : word.length();
|
||||
if (offset > fReplacementOffset + wordLength)
|
||||
if (offset >= fReplacementOffset + wordLength)
|
||||
return false;
|
||||
|
||||
try {
|
||||
|
|
|
@ -282,7 +282,7 @@ public class DOMCompletionProposalComputer extends ParsingBasedProposalComputer
|
|||
} else if (binding instanceof IEnumerator) {
|
||||
proposals.add(createProposal(name, name, getImage(binding), baseRelevance + RelevanceConstants.ENUMERATOR_TYPE_RELEVANCE, cContext));
|
||||
} else {
|
||||
proposals.add(createProposal(name, name, getImage(binding), baseRelevance, cContext));
|
||||
proposals.add(createProposal(name, name, getImage(binding), baseRelevance + RelevanceConstants.DEFAULT_TYPE_RELEVANCE, cContext));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,373 @@
|
|||
/*******************************************************************************
|
||||
* 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.contentassist;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.core.resources.IContainer;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.resources.IResource;
|
||||
import org.eclipse.core.resources.IResourceProxy;
|
||||
import org.eclipse.core.resources.IResourceProxyVisitor;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.IPath;
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.core.runtime.Path;
|
||||
import org.eclipse.jface.resource.ImageDescriptor;
|
||||
import org.eclipse.jface.text.BadLocationException;
|
||||
import org.eclipse.jface.text.IDocument;
|
||||
import org.eclipse.jface.text.ITypedRegion;
|
||||
import org.eclipse.jface.text.TextUtilities;
|
||||
import org.eclipse.swt.graphics.Image;
|
||||
|
||||
import org.eclipse.cdt.core.model.CoreModel;
|
||||
import org.eclipse.cdt.core.model.IInclude;
|
||||
import org.eclipse.cdt.core.model.ITranslationUnit;
|
||||
import org.eclipse.cdt.core.parser.IExtendedScannerInfo;
|
||||
import org.eclipse.cdt.core.parser.IScannerInfo;
|
||||
import org.eclipse.cdt.ui.CUIPlugin;
|
||||
import org.eclipse.cdt.ui.text.ICPartitions;
|
||||
import org.eclipse.cdt.ui.text.contentassist.ContentAssistInvocationContext;
|
||||
import org.eclipse.cdt.ui.text.contentassist.ICompletionProposalComputer;
|
||||
|
||||
import org.eclipse.cdt.internal.ui.viewsupport.CElementImageProvider;
|
||||
|
||||
/**
|
||||
* A proposal computer for include directives.
|
||||
*
|
||||
* @since 5.0
|
||||
*/
|
||||
public class InclusionProposalComputer implements ICompletionProposalComputer {
|
||||
|
||||
private String fErrorMessage;
|
||||
|
||||
public List computeCompletionProposals(ContentAssistInvocationContext context, IProgressMonitor monitor) {
|
||||
List<CCompletionProposal> proposals= Collections.emptyList();
|
||||
fErrorMessage= null;
|
||||
|
||||
if (context instanceof CContentAssistInvocationContext) {
|
||||
CContentAssistInvocationContext cContext= (CContentAssistInvocationContext) context;
|
||||
if (inIncludeDirective(cContext)) {
|
||||
// add include file proposals
|
||||
proposals= new ArrayList<CCompletionProposal>();
|
||||
try {
|
||||
addInclusionProposals(cContext, proposals);
|
||||
} catch (Exception exc) {
|
||||
fErrorMessage= exc.getMessage();
|
||||
CUIPlugin.log(exc);
|
||||
}
|
||||
}
|
||||
}
|
||||
return proposals;
|
||||
}
|
||||
|
||||
public List computeContextInformation(ContentAssistInvocationContext context, IProgressMonitor monitor) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getErrorMessage() {
|
||||
return fErrorMessage;
|
||||
}
|
||||
|
||||
public void sessionEnded() {
|
||||
}
|
||||
|
||||
public void sessionStarted() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether the invocation offset is inside the file name part if an include directive.
|
||||
*
|
||||
* @param context the invocation context
|
||||
* @return <code>true</code> if the invocation offset is inside or before the directive keyword
|
||||
*/
|
||||
private boolean inIncludeDirective(CContentAssistInvocationContext context) {
|
||||
IDocument doc = context.getDocument();
|
||||
int offset = context.getInvocationOffset();
|
||||
|
||||
try {
|
||||
final ITypedRegion partition= TextUtilities.getPartition(doc, ICPartitions.C_PARTITIONING, offset, true);
|
||||
if (ICPartitions.C_PREPROCESSOR.equals(partition.getType())) {
|
||||
String ppPrefix= doc.get(partition.getOffset(), offset - partition.getOffset());
|
||||
if (ppPrefix.matches("\\s*#\\s*include\\s*[\"<][^\">]*")) { //$NON-NLS-1$
|
||||
// we are inside the file name part of the include directive
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
} catch (BadLocationException exc) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void addInclusionProposals(CContentAssistInvocationContext context, List<CCompletionProposal> proposals) throws Exception {
|
||||
if (context.isContextInformationStyle()) {
|
||||
return;
|
||||
}
|
||||
String prefix;
|
||||
boolean angleBrackets= false;
|
||||
prefix = computeIncludePrefix(context);
|
||||
if (prefix.length() > 0) {
|
||||
angleBrackets= prefix.charAt(0) == '<';
|
||||
prefix= prefix.substring(1);
|
||||
}
|
||||
IPath prefixPath= new Path(prefix);
|
||||
final ITranslationUnit tu= context.getTranslationUnit();
|
||||
String[] potentialIncludes= collectIncludeFiles(tu, prefixPath, angleBrackets);
|
||||
if (potentialIncludes.length > 0) {
|
||||
IInclude[] includes= context.getTranslationUnit().getIncludes();
|
||||
Set<String> alreadyIncluded= new HashSet<String>();
|
||||
for (int i = 0; i < includes.length; i++) {
|
||||
IInclude includeDirective= includes[i];
|
||||
alreadyIncluded.add(includeDirective.getElementName());
|
||||
}
|
||||
Image image = getImage(CElementImageProvider.getIncludeImageDescriptor());
|
||||
for (int i = 0; i < potentialIncludes.length; i++) {
|
||||
String include= potentialIncludes[i];
|
||||
if (alreadyIncluded.add(include)) {
|
||||
final char openingBracket= angleBrackets ? '<' : '"';
|
||||
final char closingBracket= angleBrackets ? '>' : '"';
|
||||
String repString= openingBracket + include;
|
||||
final String dispString= repString + closingBracket;
|
||||
int repLength = prefix.length() + 1;
|
||||
int repOffset= context.getInvocationOffset() - repLength;
|
||||
final boolean needClosingBracket= context.getDocument().getChar(repOffset + repLength) != closingBracket;
|
||||
if (needClosingBracket) {
|
||||
repString += closingBracket;
|
||||
}
|
||||
final boolean isDir= include.endsWith("/"); //$NON-NLS-1$
|
||||
final int relevance= computeRelevance(prefix, include) + (isDir ? 0 : 1);
|
||||
final CCompletionProposal proposal= createProposal(repOffset, repLength, repString, dispString, image, relevance, context);
|
||||
if (!isDir && !needClosingBracket) {
|
||||
// put cursor behind closing bracket
|
||||
proposal.setCursorPosition(repString.length() + 1);
|
||||
}
|
||||
proposals.add(proposal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect potential include files for the given translation unit.
|
||||
*
|
||||
* @param tu the translation unit to include the file
|
||||
* @param prefixPath the path part to match the sub-directory and file name
|
||||
* @param angleBrackets whether angle brackets enclose the include file name
|
||||
* @return an array of incude file names
|
||||
* @throws CoreException
|
||||
*/
|
||||
private String[] collectIncludeFiles(final ITranslationUnit tu, IPath prefixPath, boolean angleBrackets) throws CoreException {
|
||||
final List<String> includeFiles= new ArrayList<String>();
|
||||
if (!angleBrackets) {
|
||||
// search in current directory
|
||||
IResource resource= tu.getResource();
|
||||
if (resource != null) {
|
||||
IContainer parent= resource.getParent();
|
||||
collectIncludeFilesFromContainer(tu, parent, prefixPath, includeFiles);
|
||||
} else {
|
||||
IPath location= tu.getLocation();
|
||||
if (location != null) {
|
||||
collectIncludeFilesFromDirectory(tu, location.removeLastSegments(1), prefixPath, includeFiles);
|
||||
}
|
||||
}
|
||||
}
|
||||
IScannerInfo info= tu.getScannerInfo(true);
|
||||
if (info != null) {
|
||||
collectIncludeFilesFromScannerInfo(tu, info, prefixPath, angleBrackets, includeFiles);
|
||||
}
|
||||
return includeFiles.toArray(new String[includeFiles.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param tu the translation unit to include the file
|
||||
* @param info the scanner info for this translation unit
|
||||
* @param prefixPath the path part to match the sub-directory and file name
|
||||
* @param angleBrackets whether angle brackets enclose the include file name
|
||||
* @param includeFiles the result list
|
||||
*/
|
||||
private void collectIncludeFilesFromScannerInfo(ITranslationUnit tu, IScannerInfo info, IPath prefixPath, boolean angleBrackets, List<String> includeFiles) {
|
||||
if (!angleBrackets && info instanceof IExtendedScannerInfo) {
|
||||
IExtendedScannerInfo extendedInfo= (IExtendedScannerInfo) info;
|
||||
String[] quoteIncludes= extendedInfo.getLocalIncludePath();
|
||||
|
||||
if (quoteIncludes != null) {
|
||||
for (int i = 0; i < quoteIncludes.length; i++) {
|
||||
IPath includeDir= new Path(quoteIncludes[i]);
|
||||
collectIncludeFilesFromDirectory(tu, includeDir, prefixPath, includeFiles);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String[] allIncludes= info.getIncludePaths();
|
||||
for (int i = 0; i < allIncludes.length; i++) {
|
||||
IPath includeDir= new Path(allIncludes[i]);
|
||||
collectIncludeFilesFromDirectory(tu, includeDir, prefixPath, includeFiles);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect include files from the given file system directory.
|
||||
*
|
||||
* @param tu the translation unit to include the file
|
||||
* @param directory the file system path of the directory
|
||||
* @param prefixPath the path part to match the sub-directory and file name
|
||||
* @param includeFiles the result list
|
||||
*/
|
||||
private void collectIncludeFilesFromDirectory(ITranslationUnit tu, IPath directory, IPath prefixPath, List<String> includeFiles) {
|
||||
final boolean isCpp= tu.isCXXLanguage();
|
||||
final String namePrefix;
|
||||
if (prefixPath.segmentCount() == 0) {
|
||||
namePrefix= ""; //$NON-NLS-1$
|
||||
} else if (prefixPath.hasTrailingSeparator()) {
|
||||
namePrefix= ""; //$NON-NLS-1$
|
||||
prefixPath= prefixPath.removeTrailingSeparator();
|
||||
directory= directory.append(prefixPath);
|
||||
} else {
|
||||
namePrefix= prefixPath.lastSegment();
|
||||
prefixPath= prefixPath.removeLastSegments(1);
|
||||
if (prefixPath.segmentCount() > 0) {
|
||||
directory= directory.append(prefixPath);
|
||||
}
|
||||
}
|
||||
final File fileDir = directory.toFile();
|
||||
if (!fileDir.exists()) {
|
||||
return;
|
||||
}
|
||||
final int prefixLength = namePrefix.length();
|
||||
final IProject project= tu.getCProject().getProject();
|
||||
File[] files= fileDir.listFiles();
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
File file = files[i];
|
||||
final String name= file.getName();
|
||||
if (name.length() >= prefixLength && namePrefix.equalsIgnoreCase(name.substring(0, prefixLength))) {
|
||||
if (file.isFile()) {
|
||||
if (isCpp) {
|
||||
if (CoreModel.isValidCXXHeaderUnitName(project, name)) {
|
||||
includeFiles.add(prefixPath.append(name).toString());
|
||||
}
|
||||
} else {
|
||||
if (CoreModel.isValidCHeaderUnitName(project, name)) {
|
||||
includeFiles.add(prefixPath.append(name).toString());
|
||||
}
|
||||
}
|
||||
} else if (file.isDirectory()) {
|
||||
includeFiles.add(prefixPath.append(name).addTrailingSeparator().toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect include files from the given resource container.
|
||||
*
|
||||
* @param tu the translation unit to include the file
|
||||
* @param parent the resource container
|
||||
* @param prefixPath the path part to match the sub-directory and file name
|
||||
* @param includeFiles the result list
|
||||
* @throws CoreException
|
||||
*/
|
||||
private void collectIncludeFilesFromContainer(final ITranslationUnit tu, IContainer parent, IPath prefixPath, final List<String> includeFiles) throws CoreException {
|
||||
final boolean isCpp= tu.isCXXLanguage();
|
||||
final String namePrefix;
|
||||
if (prefixPath.segmentCount() == 0) {
|
||||
namePrefix= ""; //$NON-NLS-1$
|
||||
} else if (prefixPath.hasTrailingSeparator()) {
|
||||
namePrefix= ""; //$NON-NLS-1$
|
||||
prefixPath= prefixPath.removeTrailingSeparator();
|
||||
parent= parent.getFolder(prefixPath);
|
||||
} else {
|
||||
namePrefix= prefixPath.lastSegment();
|
||||
prefixPath= prefixPath.removeLastSegments(1);
|
||||
if (prefixPath.segmentCount() > 0) {
|
||||
parent= parent.getFolder(prefixPath);
|
||||
}
|
||||
}
|
||||
if (!parent.exists()) {
|
||||
return;
|
||||
}
|
||||
final IPath cPrefixPath= prefixPath;
|
||||
final int prefixLength = namePrefix.length();
|
||||
final IProject project= tu.getCProject().getProject();
|
||||
parent.accept(new IResourceProxyVisitor() {
|
||||
public boolean visit(IResourceProxy proxy) throws CoreException {
|
||||
final String name= proxy.getName();
|
||||
if (name.length() < prefixLength && namePrefix.equalsIgnoreCase(name.substring(0, prefixLength))) {
|
||||
if (proxy.getType() == IResource.FILE) {
|
||||
if (isCpp) {
|
||||
if (CoreModel.isValidCXXHeaderUnitName(project, name)) {
|
||||
includeFiles.add(cPrefixPath.append(name).toString());
|
||||
}
|
||||
} else {
|
||||
if (CoreModel.isValidCHeaderUnitName(project, name)) {
|
||||
includeFiles.add(cPrefixPath.append(name).toString());
|
||||
}
|
||||
}
|
||||
} else if (proxy.getType() == IResource.FOLDER) {
|
||||
includeFiles.add(cPrefixPath.append(name).addTrailingSeparator().toString());
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}}, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the file name portion in an incomplete include directive.
|
||||
*
|
||||
* @param context
|
||||
* @return the file name portion including the opening bracket or quote
|
||||
* @throws BadLocationException
|
||||
*/
|
||||
private String computeIncludePrefix(CContentAssistInvocationContext context) throws BadLocationException {
|
||||
IDocument document= context.getDocument();
|
||||
if (document == null)
|
||||
return null;
|
||||
int end= context.getInvocationOffset();
|
||||
int start= end;
|
||||
while (--start >= 0) {
|
||||
final char ch= document.getChar(start);
|
||||
if (ch == '"' || ch == '<')
|
||||
break;
|
||||
}
|
||||
return document.get(start, end - start);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compute base relevance depending on quality of name / prefix match.
|
||||
*
|
||||
* @param prefix the completion pefix
|
||||
* @param match the matching identifier
|
||||
* @return a relevance value inidicating the quality of the name match
|
||||
*/
|
||||
protected int computeRelevance(String prefix, String match) {
|
||||
int baseRelevance= 0;
|
||||
boolean caseMatch= prefix.length() > 0 && match.startsWith(prefix);
|
||||
if (caseMatch) {
|
||||
baseRelevance += RelevanceConstants.CASE_MATCH_RELEVANCE;
|
||||
}
|
||||
return baseRelevance;
|
||||
}
|
||||
|
||||
private CCompletionProposal createProposal(int repOffset, int repLength, String repString, String dispString, Image image, int relevance, CContentAssistInvocationContext context) {
|
||||
return new CCompletionProposal(repString, repOffset, repLength, image, dispString, dispString, relevance, context.getViewer());
|
||||
}
|
||||
|
||||
private Image getImage(ImageDescriptor desc) {
|
||||
return desc != null ? CUIPlugin.getImageDescriptorRegistry().get(desc) : null;
|
||||
}
|
||||
|
||||
}
|
|
@ -103,15 +103,15 @@ public abstract class ParsingBasedProposalComputer implements ICompletionProposa
|
|||
* @return a relevance value inidicating the quality of the name match
|
||||
*/
|
||||
protected int computeBaseRelevance(String prefix, String match) {
|
||||
int baseRelevance= RelevanceConstants.DEFAULT_TYPE_RELEVANCE;
|
||||
boolean caseMatch= prefix.length() > 0 && match.startsWith(prefix);
|
||||
if (caseMatch) {
|
||||
baseRelevance += RelevanceConstants.CASE_MATCH_RELEVANCE;
|
||||
return RelevanceConstants.CASE_MATCH_RELEVANCE;
|
||||
} else {
|
||||
boolean exactNameMatch= match.equalsIgnoreCase(prefix);
|
||||
if (exactNameMatch) {
|
||||
return RelevanceConstants.EXACT_NAME_MATCH_RELEVANCE;
|
||||
}
|
||||
}
|
||||
boolean exactNameMatch= match.equalsIgnoreCase(prefix);
|
||||
if (exactNameMatch) {
|
||||
baseRelevance += RelevanceConstants.EXACT_NAME_MATCH_RELEVANCE;
|
||||
}
|
||||
return baseRelevance;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,8 @@ public interface RelevanceConstants {
|
|||
final int NAMESPACE_TYPE_RELEVANCE = 50;
|
||||
final int ENUMERATOR_TYPE_RELEVANCE = 40;
|
||||
final int ENUMERATION_TYPE_RELEVANCE = 30;
|
||||
final int MACRO_TYPE_RELEVANCE = 20;
|
||||
final int DEFAULT_TYPE_RELEVANCE = 20;
|
||||
final int MACRO_TYPE_RELEVANCE = 15;
|
||||
|
||||
/** Relevance constant for (key-)word proposals */
|
||||
final int KEYWORD_TYPE_RELEVANCE = 10;
|
||||
|
@ -42,5 +43,4 @@ public interface RelevanceConstants {
|
|||
/** Relevance constant for editor template proposals */
|
||||
final int TEMPLATE_TYPE_RELEVANCE = 5;
|
||||
|
||||
final int DEFAULT_TYPE_RELEVANCE = 0;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue