From bfd296013fa98c7dd7f36dd744d3d3434e788031 Mon Sep 17 00:00:00 2001 From: Anton Leherbauer Date: Thu, 27 Mar 2008 14:10:57 +0000 Subject: [PATCH] 113568: [Content Assist] proposals for include directives --- .../AbstractContentAssistTest.java | 60 +-- .../text/contentassist2/CompletionTests.java | 77 ++++ core/org.eclipse.cdt.ui/plugin.xml | 9 + .../contentassist/CCompletionProposal.java | 10 +- .../DOMCompletionProposalComputer.java | 2 +- .../InclusionProposalComputer.java | 373 ++++++++++++++++++ .../ParsingBasedProposalComputer.java | 14 +- .../contentassist/RelevanceConstants.java | 4 +- 8 files changed, 508 insertions(+), 41 deletions(-) create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/InclusionProposalComputer.java diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/AbstractContentAssistTest.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/AbstractContentAssistTest.java index f201f0da458..15d0bb59038 100644 --- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/AbstractContentAssistTest.java +++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/AbstractContentAssistTest.java @@ -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 filtered= new ArrayList(); 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; diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/CompletionTests.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/CompletionTests.java index 8563fe7fc3d..87528ed007a 100644 --- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/CompletionTests.java +++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/CompletionTests.java @@ -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 includeDirs= new HashSet(); + 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()]); + } } diff --git a/core/org.eclipse.cdt.ui/plugin.xml b/core/org.eclipse.cdt.ui/plugin.xml index 6a1d64c0198..e2ebd4df889 100644 --- a/core/org.eclipse.cdt.ui/plugin.xml +++ b/core/org.eclipse.cdt.ui/plugin.xml @@ -2184,6 +2184,15 @@ + + + + + = 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 { diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/DOMCompletionProposalComputer.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/DOMCompletionProposalComputer.java index 01fec64246c..7f433b662cc 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/DOMCompletionProposalComputer.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/DOMCompletionProposalComputer.java @@ -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)); } } } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/InclusionProposalComputer.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/InclusionProposalComputer.java new file mode 100644 index 00000000000..c29ce55502c --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/InclusionProposalComputer.java @@ -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 proposals= Collections.emptyList(); + fErrorMessage= null; + + if (context instanceof CContentAssistInvocationContext) { + CContentAssistInvocationContext cContext= (CContentAssistInvocationContext) context; + if (inIncludeDirective(cContext)) { + // add include file proposals + proposals= new ArrayList(); + 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 true 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 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 alreadyIncluded= new HashSet(); + 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 includeFiles= new ArrayList(); + 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 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 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 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; + } + +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/ParsingBasedProposalComputer.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/ParsingBasedProposalComputer.java index 93bd3af03f4..f5c0c912e1e 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/ParsingBasedProposalComputer.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/ParsingBasedProposalComputer.java @@ -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; } } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/RelevanceConstants.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/RelevanceConstants.java index 4cae59e72c4..e31ebc08023 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/RelevanceConstants.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/RelevanceConstants.java @@ -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; }