From df420139a37f3fde4162641cec2e8314ac5c149c Mon Sep 17 00:00:00 2001 From: Markus Schorn Date: Wed, 23 Feb 2011 16:08:53 +0000 Subject: [PATCH] Bug 173458: Camel case based content assist, by Jens Elmenthaler. --- .../ContentAssistMatcherFactoryTest.java | 75 ++++++ .../core/parser/tests/ParserTestSuite.java | 5 +- .../core/parser/tests/SegmentMatcherTest.java | 167 +++++++++++++ .../tests/prefix/BasicCompletionTest.java | 43 +++- .../index/tests/EmptyIndexFragment.java | 9 +- .../org/eclipse/cdt/core/index/IIndex.java | 17 +- .../util/ContentAssistMatcherFactory.java | 158 ++++++++++++ .../parser/util/IContentAssistMatcher.java | 50 ++++ .../cdt/core/parser/util/SegmentMatcher.java | 236 ++++++++++++++++++ .../internal/core/dom/parser/c/CScope.java | 10 +- .../internal/core/dom/parser/c/CVisitor.java | 8 +- .../dom/parser/cpp/CPPASTQualifiedName.java | 6 +- .../core/dom/parser/cpp/CPPClassScope.java | 6 +- .../core/dom/parser/cpp/CPPClosureType.java | 8 +- .../core/dom/parser/cpp/CPPScope.java | 10 +- .../cdt/internal/core/index/CIndex.java | 31 ++- .../cdt/internal/core/index/EmptyCIndex.java | 7 +- .../internal/core/index/IIndexFragment.java | 11 +- .../eclipse/cdt/internal/core/pdom/PDOM.java | 32 ++- .../cdt/internal/core/pdom/PDOMProxy.java | 9 + .../core/pdom/dom/BindingCollector.java | 28 ++- .../pdom/dom/MacroContainerCollector.java | 61 +++-- .../core/pdom/dom/NamedNodeCollector.java | 59 +++-- .../internal/core/pdom/dom/PDOMLinkage.java | 5 +- .../core/pdom/dom/cpp/PDOMCPPClassScope.java | 10 +- .../core/pdom/dom/cpp/PDOMCPPEnumScope.java | 7 +- .../core/pdom/dom/cpp/PDOMCPPNamespace.java | 9 +- .../src/org/eclipse/cdt/core/CCorePlugin.java | 8 +- .../cdt/core/CCorePreferenceConstants.java | 10 +- .../core/CCorePreferenceInitializer.java | 6 +- .../text/contentassist2/CompletionTests.java | 21 +- .../CompletionTests_PlainC.java | 7 +- .../AbstractMixedPreferencePage.java | 103 ++++++++ .../preferences/CodeAssistPreferencePage.java | 29 ++- .../ui/preferences/PreferencesMessages.java | 2 + .../PreferencesMessages.properties | 2 + .../contentassist/CCompletionProposal.java | 18 +- .../DOMCompletionProposalComputer.java | 45 ++-- .../InclusionProposalComputer.java | 11 +- 39 files changed, 1212 insertions(+), 127 deletions(-) create mode 100644 core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ContentAssistMatcherFactoryTest.java create mode 100644 core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/SegmentMatcherTest.java create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/ContentAssistMatcherFactory.java create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/IContentAssistMatcher.java create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/SegmentMatcher.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/AbstractMixedPreferencePage.java diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ContentAssistMatcherFactoryTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ContentAssistMatcherFactoryTest.java new file mode 100644 index 00000000000..f5888e9a8e8 --- /dev/null +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ContentAssistMatcherFactoryTest.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * Copyright (c) 2011 Tomasz Wesolowski 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: + * Jens Elmenthaler - initial implementation + * http://bugs.eclipse.org/173458 (camel case completion) + *******************************************************************************/ + +package org.eclipse.cdt.core.parser.tests; + +import junit.framework.TestCase; + +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.CCorePreferenceConstants; +import org.eclipse.cdt.core.parser.util.ContentAssistMatcherFactory; +import org.eclipse.cdt.core.parser.util.IContentAssistMatcher; +import org.eclipse.core.runtime.preferences.InstanceScope; + +public class ContentAssistMatcherFactoryTest extends TestCase { + + @Override + protected void tearDown() throws Exception { + InstanceScope.INSTANCE.getNode(CCorePlugin.PLUGIN_ID).remove( + CCorePreferenceConstants.SHOW_CAMEL_CASE_MATCHES); + super.tearDown(); + } + + public void testCamelCasePreference() { + // Default is show camel case matches on + assertTrue(match("foo", "fooBar")); + assertTrue(match("fB", "fooBar")); + + setShowCamelCaseMatches(false); + + assertTrue(match("foo", "fooBar")); + assertFalse(match("fB", "fooBar")); + + setShowCamelCaseMatches(true); + + assertTrue(match("foo", "fooBar")); + assertTrue(match("fB", "fooBar")); + } + + public void testCamelCaseMatcher() { + setShowCamelCaseMatches(true); + IContentAssistMatcher matcher = ContentAssistMatcherFactory + .getInstance().createMatcher("fB"); + + assertEquals("f", String.valueOf(matcher.getPrefixForBinarySearch())); + assertTrue(matcher.matchRequiredAfterBinarySearch()); + } + + public void testPrefixMatcher() { + setShowCamelCaseMatches(true); + IContentAssistMatcher matcher = ContentAssistMatcherFactory + .getInstance().createMatcher("foo"); + + assertEquals("foo", String.valueOf(matcher.getPrefixForBinarySearch())); + assertFalse(matcher.matchRequiredAfterBinarySearch()); + } + + private void setShowCamelCaseMatches(boolean enabled) { + InstanceScope.INSTANCE.getNode(CCorePlugin.PLUGIN_ID).putBoolean( + CCorePreferenceConstants.SHOW_CAMEL_CASE_MATCHES, enabled); + } + + private boolean match(String pattern, String name) { + return ContentAssistMatcherFactory.getInstance().match( + pattern.toCharArray(), name.toCharArray()); + } +} diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ParserTestSuite.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ParserTestSuite.java index 654a6775e51..44e607345d4 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ParserTestSuite.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ParserTestSuite.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2002, 2008 IBM Corporation and others. + * Copyright (c) 2002, 2011 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 @@ -7,6 +7,7 @@ * * Contributors: * IBM Rational Software - Initial API and implementation + * Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion) *******************************************************************************/ package org.eclipse.cdt.core.parser.tests; @@ -29,6 +30,8 @@ public class ParserTestSuite extends TestCase { TestSuite suite= new TestSuite(ParserTestSuite.class.getName()); suite.addTestSuite(ArrayUtilsTest.class); suite.addTestSuite(CharArrayUtilsTest.class); + suite.addTestSuite(SegmentMatcherTest.class); + suite.addTestSuite(ContentAssistMatcherFactoryTest.class); suite.addTestSuite(CModelElementsTests.class); suite.addTestSuite(StructuralCModelElementsTests.class); suite.addTestSuite(ObjectMapTest.class); diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/SegmentMatcherTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/SegmentMatcherTest.java new file mode 100644 index 00000000000..ef76fdb36cf --- /dev/null +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/SegmentMatcherTest.java @@ -0,0 +1,167 @@ +/******************************************************************************* + * Copyright (c) 2011 Tomasz Wesolowski 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: + * Tomasz Wesolowski - initial API and implementation + * Jens Elmenthaler - further tweaking + *******************************************************************************/ + +package org.eclipse.cdt.core.parser.tests; + +import junit.framework.TestCase; + +import org.eclipse.cdt.core.parser.util.SegmentMatcher; + +public class SegmentMatcherTest extends TestCase { + + + public void testSimple() { + + assertTrue(matchSegments("", "fooBarBaz")); + assertTrue(matchSegments("fBB", "fooBarBaz")); + assertTrue(matchSegments("fooBB", "fooBarBaz")); + assertTrue(matchSegments("foBaBaz", "fooBarBaz")); + assertTrue(matchSegments("fBBaz", "fooBarBaz")); + assertTrue(matchSegments("fooBarBaz", "fooBarBaz")); + assertTrue(matchSegments("foo", "fooBarBaz")); + assertTrue(matchSegments("fooB", "fooBarBaz")); + assertTrue(matchSegments("fBBaz", "fooBarBaz")); + assertTrue(matchSegments("fooB", "fooBarBaz")); + assertTrue(matchSegments("fBBaz", "fooBarBaz")); + // Improvement compared to JDT: an all upper case abbreviation should + // also match as a single segment. + assertTrue(matchSegments("fBBaz", "fooBARBaz")); + // Improvement compared to JDT: you don't need to specify all segments + // in between. + assertTrue(matchSegments("fBaz", "fooBARBaz")); + + assertFalse(matchSegments("FooBarBaz", "fooBarBaz")); + assertFalse(matchSegments("fooBARBaz", "fooBarBaz")); + assertTrue(matchSegments("fooBarbaz", "fooBarBaz")); + assertFalse(matchSegments("barBaz", "fooBarBaz")); + assertFalse(matchSegments("BarBaz", "fooBarBaz")); + assertTrue(matchSegments("fBaz", "fooBarBaz")); + assertFalse(matchSegments("fBaBar", "fooBarBaz")); + assertFalse(matchSegments("fBBB", "fooBarBaz")); + assertFalse(matchSegments("fBBBarBaz", "fooBarBaz")); + assertFalse(matchSegments("foooBarBaz", "fooBarBaz")); + assertFalse(matchSegments("foBrBaz", "fooBarBaz")); + + } + + public void testSuffix() { + + assertTrue(matchSegments("fooBar", "fooBar123")); + assertTrue(matchSegments("fooBar", "fooBarrr")); + assertTrue(matchSegments("fooBar", "fooBarr__")); + + } + + public void testNumeric() { + + assertTrue(matchSegments("fBBaz", "foo29BarBaz")); + assertTrue(matchSegments("fBBaz", "fooBar100Baz10")); + assertTrue(matchSegments("fB100Baz1", "fooBar100Baz10")); + assertTrue(matchSegments("fB100Baz10", "fooBar100Baz10")); + assertTrue(matchSegments("fooBar100Baz10", "fooBar100Baz10")); + + assertFalse(matchSegments("fBar100Ba", "fooBarBaz")); + assertTrue(matchSegments("f100Baz", "fooBar100Baz10")); + assertFalse(matchSegments("fB1000Baz", "fooBar100Baz")); + assertFalse(matchSegments("sV", "seed48")); + + } + + public void testSeparator() { + + assertTrue(matchSegments("fBB", "foo_Bar_Baz")); + assertTrue(matchSegments("fBB", "foo_BarBaz")); + assertTrue(matchSegments("fBB", "foo_bar_baz")); + // Improvement compared to JDT: + assertTrue(matchSegments("FBB", "FOO_BAR_BAZ")); + + assertTrue(matchSegments("fBB", "foo__barBaz")); + assertTrue(matchSegments("fBB", "foo__bar__baz")); + assertTrue(matchSegments("fB_B", "foo__bar__Baz")); + assertTrue(matchSegments("f__b", "foo__bar")); + + assertFalse(matchSegments("fB_B", "foo__bar__baz")); + assertFalse(matchSegments("f___b", "foo__bar")); + assertFalse(matchSegments("f__bb", "foo__bar__baz")); + + assertFalse(matchSegments("f_B_B", "fooBarBaz")); + assertFalse(matchSegments("f_B", "foo_bar")); + assertFalse(matchSegments("foo_B", "foo_bar")); + assertFalse(matchSegments("foo_Bar", "foo_bar")); + assertFalse(matchSegments("fO_bar", "foo_bar")); + assertFalse(matchSegments("f__b", "foo_bar")); + + } + + public void testPrefixChars() { + + assertFalse(matchSegments("$asd","_asd")); + assertFalse(matchSegments("_$$","__")); + assertFalse(matchSegments("__$","__")); + + // require everything to be exactly the same from start up until the first section + assertTrue(matchSegments("__f", "__fooBar")); + assertTrue(matchSegments("__fooB", "__fooBar")); + assertFalse(matchSegments("_fooB", "__fooBar")); + assertFalse(matchSegments("_FooB", "__fooBar")); + assertFalse(matchSegments("_$fooB", "__fooBar")); + + assertTrue(matchSegments("___", "___")); + assertFalse(matchSegments("$__", "___")); + assertFalse(matchSegments("__$", "___")); + assertTrue(matchSegments("__", "___")); + assertFalse(matchSegments("____", "___")); + + } + + public void testAbbreviations() { + assertTrue(matchSegments("IFB", "IFooBar")); + assertTrue(matchSegments("IFoB", "IFooBar")); + assertTrue(matchSegments("XYZ", "XYZFooBar")); + } + + public void testSingleSegment() { + assertTrue(matchSegments("foo", "fooBar")); + assertFalse(matchSegments("bar", "fooBar")); + } + + public void testGetPrefixForBinarySearch() { + // Segments can be skipped, because of that the first letter as well + // as the leading separator must not be added to the binary search prefix. + assertEquals("foo", getPrefixForBinarySearch("fooBar")); + assertEquals("foo", getPrefixForBinarySearch("foo6")); + assertEquals("foo", getPrefixForBinarySearch("foo_")); + assertEquals("foo", getPrefixForBinarySearch("foo$")); + assertEquals("___", getPrefixForBinarySearch("___")); + assertEquals("___foo", getPrefixForBinarySearch("___fooBar")); + assertEquals("___foo", getPrefixForBinarySearch("___foo3")); + assertEquals("___foo", getPrefixForBinarySearch("___foo_")); + assertEquals("___foo", getPrefixForBinarySearch("___foo$")); + assertEquals("$__", getPrefixForBinarySearch("$__")); + assertEquals("$__foo", getPrefixForBinarySearch("$__fooBar")); + assertEquals("$__foo", getPrefixForBinarySearch("$__foo3")); + assertEquals("$__foo", getPrefixForBinarySearch("$__foo_")); + } + + /** + * Only checks segment matching (i.e. without case-insensitive prefix matching) + */ + private boolean matchSegments(String pattern, String name) { + SegmentMatcher matcher = new SegmentMatcher(pattern.toCharArray()); + return matcher.matchSegments(name.toCharArray()); + } + + private String getPrefixForBinarySearch(String pattern) { + SegmentMatcher matcher = new SegmentMatcher(pattern.toCharArray()); + return String.valueOf(matcher.getPrefixForBinarySearch()); + } +} diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/prefix/BasicCompletionTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/prefix/BasicCompletionTest.java index ddeafdc6bf3..a93c278b44c 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/prefix/BasicCompletionTest.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/prefix/BasicCompletionTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2010 IBM Corporation and others. + * Copyright (c) 2004, 2011 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 @@ -9,6 +9,7 @@ * IBM Corporation - initial API and implementation * Bryan Wilkinson (QNX) * Markus Schorn (Wind River Systems) + * Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion) *******************************************************************************/ package org.eclipse.cdt.core.parser.tests.prefix; @@ -296,4 +297,44 @@ public class BasicCompletionTest extends CompletionTestBase { checkNonPrefixCompletion(code, true, expected); } + // typedef int FooBar; + // typedef int Foo_Bar; + // FB + public void testCamelCaseCompletion_CScope() throws Exception { + String code = getAboveComment(); + String[] expected= {"FooBar", "Foo_Bar"}; + checkCompletion(code, false, expected); + } + + // typedef int FooBar; + // typedef int Foo_Bar; + // FB + public void testCamelCaseCompletion_CPPScope() throws Exception { + String code = getAboveComment(); + String[] expected= {"FooBar", "Foo_Bar"}; + checkCompletion(code, true, expected); + } + + // class FooBar { + // FooBar(); + // } + // FooBar::FB + public void testCamelCaseCompletion_CPPASTQualifiedName_CPPClassScope() throws Exception { + String code = getAboveComment(); + String[] expected= {"FooBar", "FooBar"}; + checkCompletion(code, true, expected); + } + + // struct s1 { + // int fooBar; + // int foo_bar; + // }; + // void test() { + // struct s1 s; + // s. + public void testCamelCaseCompletion_CVisitor() throws Exception { + String code = getAboveComment(); + String[] expected= {"fooBar", "foo_bar"}; + checkCompletion(code, false, expected); + } } diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/EmptyIndexFragment.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/EmptyIndexFragment.java index 3f098b03fac..aa1a2b965dd 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/EmptyIndexFragment.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/EmptyIndexFragment.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2010 Symbian Software Ltd. and others. + * Copyright (c) 2007, 2011 Symbian Software Ltd. 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 @@ -9,6 +9,7 @@ * Andrew Ferguson (Symbian) - initial API and implementation * Markus Schorn (Wind River Systems) * Sergey Prigogin (Google) + * Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion) *******************************************************************************/ package org.eclipse.cdt.internal.index.tests; @@ -68,6 +69,12 @@ public class EmptyIndexFragment implements IIndexFragment { return IIndexFragmentBinding.EMPTY_INDEX_BINDING_ARRAY; } + public IIndexFragmentBinding[] findBindingsForContentAssist(char[] prefix, + boolean filescope, IndexFilter filter, IProgressMonitor monitor) + throws CoreException { + return IIndexFragmentBinding.EMPTY_INDEX_BINDING_ARRAY; + } + public IIndexMacro[] findMacros(char[] name, boolean isPrefix, boolean caseSensitive, IndexFilter filter, IProgressMonitor monitor) { return IIndexMacro.EMPTY_INDEX_MACRO_ARRAY; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndex.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndex.java index 9cc4978e387..9ae50211c0d 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndex.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndex.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2010 Wind River Systems, Inc. and others. + * Copyright (c) 2006, 2011 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 @@ -10,6 +10,7 @@ * Andrew Ferguson (Symbian) * Bryan Wilkinson (QNX) * Sergey Prigogin (Google) + * Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion) *******************************************************************************/ package org.eclipse.cdt.core.index; @@ -326,7 +327,19 @@ public interface IIndex { * @throws CoreException */ public IIndexBinding[] findBindingsForPrefix(char[] prefix, boolean fileScopeOnly, IndexFilter filter, IProgressMonitor monitor) throws CoreException; - + + /** + * Searches for all bindings that are valid completions to the given prefix. + * @param prefix the text to be completed. + * @param fileScopeOnly if true, only bindings at file scope are returned + * @param filter a filter that allows for skipping parts of the index + * @param monitor a monitor for progress reporting and cancellation, may be null + * @return an array of bindings that complete the given text + * @throws CoreException + * @since 5.3 + */ + public IIndexBinding[] findBindingsForContentAssist(char[] prefix, boolean fileScopeOnly, IndexFilter filter, IProgressMonitor monitor) throws CoreException; + /** * Searches for all names that resolve to the given binding. You can limit the result to references, declarations * or definitions, or a combination of those. diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/ContentAssistMatcherFactory.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/ContentAssistMatcherFactory.java new file mode 100644 index 00000000000..8bf2566751a --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/ContentAssistMatcherFactory.java @@ -0,0 +1,158 @@ +/******************************************************************************* + * Copyright (c) 2011 Jens Elmenthaler 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: + * Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion) + *******************************************************************************/ +package org.eclipse.cdt.core.parser.util; + +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.CCorePreferenceConstants; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.preferences.IEclipsePreferences; +import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener; +import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent; +import org.eclipse.core.runtime.preferences.IPreferencesService; +import org.eclipse.core.runtime.preferences.InstanceScope; + + +/** + * The facade to the pattern matching algorithms of content assist. + * + * @author Jens Elmenthaler + * + * @noextend This class is not intended to be subclassed by clients. + * @since 5.3 + */ +public class ContentAssistMatcherFactory { + + private static ContentAssistMatcherFactory instance = null; + + private boolean showCamelCaseMatches; + + private final IPreferenceChangeListener preferencesListener = new IPreferenceChangeListener() { + + public void preferenceChange(PreferenceChangeEvent event) { + String prop = event.getKey(); + if (prop.equals(CCorePreferenceConstants.SHOW_CAMEL_CASE_MATCHES)) { + updateOnPreferences(); + } + } + }; + + private static class CamelCaseMatcher implements IContentAssistMatcher { + + private final SegmentMatcher matcher; + + public CamelCaseMatcher(char[] pattern) { + matcher = new SegmentMatcher(pattern); + } + + public char[] getPrefixForBinarySearch() { + return matcher.getPrefixForBinarySearch(); + } + + public boolean matchRequiredAfterBinarySearch() { + return matcher.matchRequiredAfterBinarySearch(); + } + + public boolean match(char[] name) { + return matcher.match(name); + } + } + + private static class PrefixMatcher implements IContentAssistMatcher { + + private final char[] prefix; + + public PrefixMatcher(char[] prefix) { + this.prefix = prefix; + } + + public char[] getPrefixForBinarySearch() { + return prefix; + } + + public boolean matchRequiredAfterBinarySearch() { + return false; + } + + public boolean match(char[] name) { + return CharArrayUtils.equals(name, 0, prefix.length, prefix, true); + } + + } + + private ContentAssistMatcherFactory() { + getPreferences().addPreferenceChangeListener( + preferencesListener); + updateOnPreferences(); + } + + public static synchronized ContentAssistMatcherFactory getInstance() { + if (instance == null) { + instance = new ContentAssistMatcherFactory(); + } + + return instance; + } + + private void shutdownInternal() { + getPreferences().removePreferenceChangeListener( + preferencesListener); + } + + /** + * @noreference This method is not intended to be referenced by clients. + */ + public static synchronized void shutdown() { + if (instance != null) { + instance.shutdownInternal(); + } + } + + private static IEclipsePreferences getPreferences() { + return InstanceScope.INSTANCE.getNode(CCorePlugin.PLUGIN_ID); + } + + private synchronized void updateOnPreferences() { + IPreferencesService prefs = Platform.getPreferencesService(); + showCamelCaseMatches = prefs.getBoolean(CCorePlugin.PLUGIN_ID, + CCorePreferenceConstants.SHOW_CAMEL_CASE_MATCHES, true, null); + } + + /** + * @param pattern The pattern for which to create a matcher. + * @return A suitable matcher. + */ + public synchronized IContentAssistMatcher createMatcher(char[] pattern) { + + return showCamelCaseMatches ? new CamelCaseMatcher(pattern) : new PrefixMatcher(pattern); + } + + /** + * @param pattern The pattern for which to create a matcher. + * @return A suitable matcher. + */ + public IContentAssistMatcher createMatcher(String pattern) { + return createMatcher(pattern.toCharArray()); + } + + /** + * A helper method to match a name against the pattern typed by the user. + * If you need to match many names at once against the same pattern, use + * {@link #createMatcher(char[])} and re-use the returned matcher instead. + * + * @param pattern The user provided pattern. + * @param name The name to match against the pattern. + * + * @return true if the name matches the given pattern. + */ + public boolean match(char[] pattern, char[] name) { + return createMatcher(pattern).match(name); + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/IContentAssistMatcher.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/IContentAssistMatcher.java new file mode 100644 index 00000000000..3d22a9f6349 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/IContentAssistMatcher.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2011 Jens Elmenthaler 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: + * Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion) + *******************************************************************************/ +package org.eclipse.cdt.core.parser.util; + +/** + * A matcher for content assist-like application to determine whether names + * match the user provided text. + * + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + * @since 5.3 + */ +public interface IContentAssistMatcher { + + /** + * The user provided text normally represents some kind of pattern. This pattern + * may not be suitable for binary searches (e.g. within the index). + * For each content assist pattern, however, there is a string that can be + * calculated and used for binary searches. + * In the compare method used by your binary search, return 0 for any string + * that starts with the returned string. + * + * @return Such a string. + */ + char[] getPrefixForBinarySearch(); + + /** + * @return If false, calling @{@link #match(char[])} can be skipped if a + * name survived a binary search using the prefix returned by + * @{@link #getPrefixForBinarySearch()} as key. + */ + boolean matchRequiredAfterBinarySearch(); + + /** + * Matches the given name following the rules of content assist. + * + * @param name + * + * @return True if the name matches. + */ + boolean match(char[] name); +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/SegmentMatcher.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/SegmentMatcher.java new file mode 100644 index 00000000000..ed3e500d6e9 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/SegmentMatcher.java @@ -0,0 +1,236 @@ +/******************************************************************************* + * Copyright (c) 2011 Tomasz Wesolowski 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: + * Tomasz Wesolowski - initial API and implementation + * Jens Elmenthaler - further tweaking + *******************************************************************************/ +package org.eclipse.cdt.core.parser.util; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * A matcher for camel case matching supporting both the camel case as well as + * he underscore notation. + * + * @noextend This class is not intended to be subclassed by clients. + * @since 5.3 + */ +public class SegmentMatcher { + + private final char[] prefixForBinarySearch; + + /** The string the any prefix match has to start with. */ + private final char[] prefixForMatching; + + /** The regular expression for a segment match. */ + private final Pattern regexp; + + /** The minimum length any name must have in order to match. */ + private final int minNameLength; + + private final boolean singleSegment; + + /** + * @param pattern + * The camel case or underscore pattern. + */ + public SegmentMatcher(char[] pattern) { + + if (pattern == null || pattern.length == 0) { + prefixForMatching = CharArrayUtils.EMPTY; + prefixForBinarySearch = CharArrayUtils.EMPTY; + regexp = null; + minNameLength = 0; + singleSegment = true; + } else { + + StringBuffer regexpBuffer = new StringBuffer("^"); //$NON-NLS-1$ + int i = 0; + int lengthOfFirstSegment = 0; + char currentChar; + int segmentCount = 0; + + // Translate each segment + while (i < pattern.length) { + + boolean separatorSpecified = false; + + // Handle prefix, i.e. anything before the first letter or digit + for (; i < pattern.length; ++i) { + currentChar = pattern[i]; + if (Character.isLetterOrDigit(currentChar)) { + break; + } else { + // Quote those characters. + regexpBuffer.append(Pattern.quote(String.valueOf(currentChar))); + separatorSpecified = true; + } + } + + if (i < pattern.length) { + // The character here is always a letter or digit. + currentChar = pattern[i]; + + if (Character.isDigit(currentChar)) { + + // Handle number segment + regexpBuffer.append(currentChar); + for (++i; i < pattern.length; ++i) { + currentChar = pattern[i]; + if (Character.isDigit(currentChar)) { + regexpBuffer.append(currentChar); + } else { + break; + } + } + + } else { + + // Handle text segment + char lower = Character.toLowerCase(currentChar); + char upper = Character.toUpperCase(currentChar); + + if ((segmentCount == 0) || separatorSpecified) { + regexpBuffer.append(currentChar); + } else { + regexpBuffer.append("(_["); //$NON-NLS-1$ + regexpBuffer.append(lower); + regexpBuffer.append(upper); + regexpBuffer.append("]|"); //$NON-NLS-1$ + regexpBuffer.append(upper); + regexpBuffer.append(')'); + } + + // Remaining letters of the segment + for (++i; i < pattern.length; ++i) { + + currentChar = pattern[i]; + if (Character.isLetter(currentChar)) { + if (Character.isUpperCase(currentChar)) { + break; + } else { + lower = currentChar; + upper = Character.toUpperCase(currentChar); + regexpBuffer.append('['); + regexpBuffer.append(lower); + regexpBuffer.append(upper); + regexpBuffer.append(']'); + } + } else { + break; + } + } + } + } + regexpBuffer.append(".*"); //$NON-NLS-1$ + + if (segmentCount == 0) { + lengthOfFirstSegment = i; + } + + ++segmentCount; + } + + regexp = Pattern.compile(regexpBuffer.toString()); + singleSegment = (segmentCount == 1); + prefixForMatching = pattern; + + // The first segment is also the binary search prefix + prefixForBinarySearch = CharArrayUtils.extract(pattern, 0, lengthOfFirstSegment); + + minNameLength = pattern.length; + } + } + + /** + * Matches the given name by prefix and segment matching. + * + * @return true if the associated pattern is a prefix-based or segment-based abbreviation of name. + */ + public boolean match(char[] name) { + if (matchPrefix(name)) { + return true; + } + + // If there is only a single segment given and prefix match failed, + // the segment match cannot pass either. So skip it. + if (singleSegment) { + return false; + } + + return matchSegments(name); + } + + /** + * Matches the given name by prefix matching. + * + * @return true if the associated pattern is a prefix-based abbreviation of name. + */ + public boolean matchPrefix(char[] name) { + return (CharArrayUtils.equals(name, 0, prefixForMatching.length, prefixForMatching, true)); + } + + /** + * Matches the given name by segment matching. + * + * @return true if the associated pattern is a segment-based abbreviation of name. + */ + public boolean matchSegments(char[] name) { + + if (name == null) { + return false; + } + + if (name.length < minNameLength) { + return false; + } + + if (regexp == null) { + return true; + } + + Matcher matcher = regexp.matcher(String.valueOf(name)); + + return matcher.find(); + } + + /** + * Matches pattern to name by prefix and segment matching. If you have to match + * against the same pattern repeatedly, create a {@link SegmentMatcher} instead + * and re-use it all the time, because this is much faster. + * + * @return true if pattern is a prefix-based or segment-based abbreviation of name + */ + public static boolean match(char[] pattern, char[] name) { + return (new SegmentMatcher(pattern)).match(name); + } + + /** + * The pattern used by this matcher is not suitable for binary searches + * (e.g. within the index). + * However, there can be calculated a string that can be used in the + * context of binary searches. + * In the compare method used by your binary search, return 0 for any string + * that starts with the returned string. + * + * @return Such a string. + */ + public char[] getPrefixForBinarySearch() { + return prefixForBinarySearch; + } + + /** + * @return If false, calling @{@link #match(char[])} can be skipped if a + * name survived a binary search using the prefix returned by + * @{@link #getPrefixForBinarySearch()} as key. + */ + boolean matchRequiredAfterBinarySearch() { + return !singleSegment; + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CScope.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CScope.java index 1f3ca719b5e..a9aecb7005a 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CScope.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CScope.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2010 IBM Corporation and others. + * Copyright (c) 2004, 2011 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 @@ -10,6 +10,7 @@ * Markus Schorn (Wind River Systems) * Bryan Wilkinson (QNX) * Andrew Ferguson (Symbian) + * Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion) *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser.c; @@ -56,6 +57,8 @@ import org.eclipse.cdt.core.index.IndexFilter; import org.eclipse.cdt.core.parser.util.ArrayUtil; import org.eclipse.cdt.core.parser.util.CharArrayObjectMap; import org.eclipse.cdt.core.parser.util.CharArrayUtils; +import org.eclipse.cdt.core.parser.util.ContentAssistMatcherFactory; +import org.eclipse.cdt.core.parser.util.IContentAssistMatcher; import org.eclipse.cdt.internal.core.dom.parser.ASTInternal; import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguousDeclarator; import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguousParameterDeclaration; @@ -327,10 +330,11 @@ public class CScope implements ICScope, IASTInternalScope { populateCache(); for (CharArrayObjectMap map : mapsToNameOrBinding) { if (prefixLookup) { + IContentAssistMatcher matcher = ContentAssistMatcherFactory.getInstance().createMatcher(c); Object[] keys = map.keyArray(); for (Object key2 : keys) { char[] key = (char[]) key2; - if (CharArrayUtils.equals(key, 0, c.length, c, true)) { + if (matcher.match(key)) { obj = ArrayUtil.append(obj, map.get(key)); } } @@ -344,7 +348,7 @@ public class CScope implements ICScope, IASTInternalScope { IIndex index = tu.getIndex(); if (index != null) { try { - IBinding[] bindings = prefixLookup ? index.findBindingsForPrefix(name.toCharArray(), true, INDEX_FILTERS[NAMESPACE_TYPE_BOTH], null) + IBinding[] bindings = prefixLookup ? index.findBindingsForContentAssist(name.toCharArray(), true, INDEX_FILTERS[NAMESPACE_TYPE_BOTH], null) : index.findBindings(name.toCharArray(), INDEX_FILTERS[NAMESPACE_TYPE_BOTH], null); if (fileSet != null) { bindings = fileSet.filterFileLocalBindings(bindings); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CVisitor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CVisitor.java index 31be5f90d60..3e6d48dd54b 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CVisitor.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CVisitor.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2010 IBM Corporation and others. + * Copyright (c) 2005, 2011 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 @@ -10,6 +10,7 @@ * Markus Schorn (Wind River Systems) * Bryan Wilkinson (QNX) * Andrew Ferguson (Symbian) + * Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion) *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser.c; @@ -89,6 +90,8 @@ import org.eclipse.cdt.core.index.IIndexFileSet; import org.eclipse.cdt.core.parser.util.ArrayUtil; import org.eclipse.cdt.core.parser.util.CharArraySet; import org.eclipse.cdt.core.parser.util.CharArrayUtils; +import org.eclipse.cdt.core.parser.util.ContentAssistMatcherFactory; +import org.eclipse.cdt.core.parser.util.IContentAssistMatcher; import org.eclipse.cdt.internal.core.dom.parser.ASTInternal; import org.eclipse.cdt.internal.core.dom.parser.ASTNode; import org.eclipse.cdt.internal.core.dom.parser.ASTQueries; @@ -609,9 +612,10 @@ public class CVisitor extends ASTQueries { if (prefix) { IBinding[] result = null; char[] p = fieldReference.getFieldName().toCharArray(); + IContentAssistMatcher matcher = ContentAssistMatcherFactory.getInstance().createMatcher(p); IField[] fields = ((ICompositeType) type).getFields(); for (IField field : fields) { - if (CharArrayUtils.equals(field.getNameCharArray(), 0, p.length, p, true)) { + if (matcher.match(field.getNameCharArray())) { result = (IBinding[]) ArrayUtil.append(IBinding.class, result, field); } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTQualifiedName.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTQualifiedName.java index 98ca1e8d652..01c44a1b427 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTQualifiedName.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTQualifiedName.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2010 IBM Corporation and others. + * Copyright (c) 2004, 2011 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 @@ -9,6 +9,7 @@ * John Camelon (IBM) - Initial API and implementation * Bryan Wilkinson (QNX) * Markus Schorn (Wind River Systems) + * Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion) *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser.cpp; @@ -41,6 +42,7 @@ import org.eclipse.cdt.core.model.IEnumeration; import org.eclipse.cdt.core.parser.Keywords; import org.eclipse.cdt.core.parser.util.ArrayUtil; import org.eclipse.cdt.core.parser.util.CharArrayUtils; +import org.eclipse.cdt.core.parser.util.ContentAssistMatcherFactory; import org.eclipse.cdt.internal.core.dom.parser.IASTInternalNameOwner; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor; @@ -329,7 +331,7 @@ public class CPPASTQualifiedName extends CPPASTNameBase private boolean nameMatches(char[] potential, char[] name, boolean isPrefix) { if (isPrefix) - return CharArrayUtils.equals(potential, 0, name.length, name, true); + return ContentAssistMatcherFactory.getInstance().match(name, potential); return CharArrayUtils.equals(potential, name); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClassScope.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClassScope.java index 62ba554c14c..1ed91896e50 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClassScope.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClassScope.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2010 IBM Corporation and others. + * Copyright (c) 2004, 2011 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 @@ -11,6 +11,7 @@ * Bryan Wilkinson (QNX) * Andrew Ferguson (Symbian) * Sergey Prigogin (Google) + * Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion) *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser.cpp; @@ -54,6 +55,7 @@ import org.eclipse.cdt.core.index.IIndexFileSet; import org.eclipse.cdt.core.parser.util.ArrayUtil; import org.eclipse.cdt.core.parser.util.CharArrayObjectMap; import org.eclipse.cdt.core.parser.util.CharArrayUtils; +import org.eclipse.cdt.core.parser.util.ContentAssistMatcherFactory; import org.eclipse.cdt.core.parser.util.ObjectSet; import org.eclipse.cdt.internal.core.dom.parser.ASTQueries; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics; @@ -240,7 +242,7 @@ public class CPPClassScope extends CPPScope implements ICPPClassScope { } IBinding[] result = null; if ((!prefixLookup && CharArrayUtils.equals(c, compName.getLookupKey())) - || (prefixLookup && CharArrayUtils.equals(compName.getLookupKey(), 0, c.length, c, true))) { + || (prefixLookup && ContentAssistMatcherFactory.getInstance().match(c, compName.getLookupKey()))) { if (shallReturnConstructors(name, prefixLookup)) { result = (IBinding[]) ArrayUtil.addAll(IBinding.class, result, getConstructors(name, resolve)); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClosureType.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClosureType.java index 554407c43a4..3a9e06d29f4 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClosureType.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClosureType.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010 Wind River Systems, Inc. and others. + * Copyright (c) 2010, 2011 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 @@ -7,6 +7,7 @@ * * Contributors: * Markus Schorn (Wind River Systems) - initial API and implementation + * Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion) *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser.cpp; @@ -45,6 +46,8 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameter; import org.eclipse.cdt.core.index.IIndexBinding; import org.eclipse.cdt.core.index.IIndexFileSet; import org.eclipse.cdt.core.parser.util.CharArrayUtils; +import org.eclipse.cdt.core.parser.util.ContentAssistMatcherFactory; +import org.eclipse.cdt.core.parser.util.IContentAssistMatcher; import org.eclipse.cdt.internal.core.dom.Linkage; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor; @@ -342,9 +345,10 @@ public class CPPClosureType extends PlatformObject implements ICPPClassType, ICP private IBinding[] getPrefixBindings(char[] name) { List result= new ArrayList(); + IContentAssistMatcher matcher = ContentAssistMatcherFactory.getInstance().createMatcher(name); for (ICPPMethod m : getMethods()) { if (!(m instanceof ICPPConstructor)) { - if (CharArrayUtils.equals(name, 0, name.length, m.getNameCharArray(), true)) { + if (matcher.match(m.getNameCharArray())) { result.add(m); } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPScope.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPScope.java index 27481f95a73..635d7c46a09 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPScope.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPScope.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2010 IBM Corporation and others. + * Copyright (c) 2004, 2011 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 @@ -10,6 +10,7 @@ * Markus Schorn (Wind River Systems) * Bryan Wilkinson (QNX) * Andrew Ferguson (Symbian) + * Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion) *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser.cpp; @@ -37,6 +38,8 @@ import org.eclipse.cdt.core.index.IndexFilter; import org.eclipse.cdt.core.parser.util.ArrayUtil; import org.eclipse.cdt.core.parser.util.CharArrayObjectMap; import org.eclipse.cdt.core.parser.util.CharArrayUtils; +import org.eclipse.cdt.core.parser.util.ContentAssistMatcherFactory; +import org.eclipse.cdt.core.parser.util.IContentAssistMatcher; import org.eclipse.cdt.core.parser.util.ObjectSet; import org.eclipse.cdt.internal.core.dom.parser.ASTInternal; import org.eclipse.cdt.internal.core.dom.parser.ProblemBinding; @@ -211,7 +214,7 @@ abstract public class CPPScope implements ICPPASTInternalScope { IndexFilter filter = IndexFilter.CPP_DECLARED_OR_IMPLICIT_NO_INSTANCE; final char[] nchars = name.getLookupKey(); IBinding[] bindings = prefixLookup ? - index.findBindingsForPrefix(nchars, true, filter, null) : + index.findBindingsForContentAssist(nchars, true, filter, null) : index.findBindings(nchars, filter, null); if (fileSet != null) { bindings= fileSet.filterFileLocalBindings(bindings); @@ -253,9 +256,10 @@ abstract public class CPPScope implements ICPPASTInternalScope { if (prefixLookup) { Object[] keys = bindings != null ? bindings.keyArray() : new Object[0]; ObjectSet all= new ObjectSet(16); + IContentAssistMatcher matcher = ContentAssistMatcherFactory.getInstance().createMatcher(c); for (Object key2 : keys) { final char[] key = (char[]) key2; - if (key != CONSTRUCTOR_KEY && CharArrayUtils.equals(key, 0, c.length, c, true)) { + if (key != CONSTRUCTOR_KEY && matcher.match(key)) { obj= bindings.get(key); if (obj instanceof ObjectSet) { all.addAll((ObjectSet) obj); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/CIndex.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/CIndex.java index 197c5e4cdca..bab6a074569 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/CIndex.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/CIndex.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2010 Wind River Systems, Inc. and others. + * Copyright (c) 2006, 2011 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 @@ -11,6 +11,7 @@ * Andrew Ferguson (Symbian) * Anton Leherbauer (Wind River Systems) * Sergey Prigogin (Google) + * Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion) *******************************************************************************/ package org.eclipse.cdt.internal.core.index; @@ -531,6 +532,34 @@ public class CIndex implements IIndex { } } + public IIndexBinding[] findBindingsForContentAssist(char[] prefix, boolean filescope, + IndexFilter filter, IProgressMonitor monitor) throws CoreException { + if (SPECIALCASE_SINGLES && fFragments.length == 1) { + return fFragments[0].findBindingsForContentAssist(prefix, filescope, filter, monitor); + } else { + List result = new ArrayList(); + ILinkage[] linkages = Linkage.getIndexerLinkages(); + for (ILinkage linkage : linkages) { + if (filter.acceptLinkage(linkage)) { + IIndexFragmentBinding[][] fragmentBindings = new IIndexFragmentBinding[fPrimaryFragmentCount][]; + for (int i = 0; i < fPrimaryFragmentCount; i++) { + try { + IBinding[] part = fFragments[i].findBindingsForContentAssist(prefix, filescope, retargetFilter(linkage, filter), monitor); + fragmentBindings[i] = new IIndexFragmentBinding[part.length]; + System.arraycopy(part, 0, fragmentBindings[i], 0, part.length); + } catch (CoreException e) { + CCorePlugin.log(e); + fragmentBindings[i] = IIndexFragmentBinding.EMPTY_INDEX_BINDING_ARRAY; + } + } + ICompositesFactory factory = getCompositesFactory(linkage.getLinkageID()); + result.add(factory.getCompositeBindings(fragmentBindings)); + } + } + return flatten(result); + } + } + public IIndexBinding[] findBindings(char[] name, boolean filescope, IndexFilter filter, IProgressMonitor monitor) throws CoreException { if (SPECIALCASE_SINGLES && fFragments.length == 1) { return fFragments[0].findBindings(name, filescope, filter, monitor); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/EmptyCIndex.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/EmptyCIndex.java index a054a92e842..ad21a190f76 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/EmptyCIndex.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/EmptyCIndex.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2010 Wind River Systems, Inc. and others. + * Copyright (c) 2006, 2011 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 @@ -10,6 +10,7 @@ * Bryan Wilkinson (QNX) * Andrew Ferguson (Symbian) * Sergey Prigogin (Google) + * Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion) *******************************************************************************/ package org.eclipse.cdt.internal.core.index; @@ -115,6 +116,10 @@ final public class EmptyCIndex implements IIndex { return IIndexBinding.EMPTY_INDEX_BINDING_ARRAY; } + public IIndexBinding[] findBindingsForContentAssist(char[] prefix, boolean filescope, IndexFilter filter, IProgressMonitor monitor) { + return IIndexBinding.EMPTY_INDEX_BINDING_ARRAY; + } + public IIndexBinding[] findBindings(char[][] names, IndexFilter filter, IProgressMonitor monitor) { return IIndexBinding.EMPTY_INDEX_BINDING_ARRAY; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IIndexFragment.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IIndexFragment.java index 79853062a05..dd0425ded2f 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IIndexFragment.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IIndexFragment.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2010 Wind River Systems, Inc. and others. + * Copyright (c) 2006, 2011 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 @@ -10,6 +10,7 @@ * Bryan Wilkinson (QNX) * Andrew Ferguson (Symbian) * Sergey Prigogin (Google) + * Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion) *******************************************************************************/ package org.eclipse.cdt.internal.core.index; @@ -213,12 +214,18 @@ public interface IIndexFragment { */ IIndexFragmentBinding[] findBindingsForPrefix(char[] prefix, boolean filescope, IndexFilter filter, IProgressMonitor monitor) throws CoreException; + /** + * Returns all bindings that would be a valid completion for the given text. + * @param monitor to report progress, may be null + */ + IIndexFragmentBinding[] findBindingsForContentAssist(char[] prefix, boolean filescope, IndexFilter filter, IProgressMonitor monitor) throws CoreException; + /** * Returns all macros with the given prefix or name, accepted by the given filter * @param monitor to report progress, may be null */ IIndexMacro[] findMacros(char[] name, boolean isPrefix, boolean caseSensitive, IndexFilter filter, IProgressMonitor monitor) throws CoreException; - + /** * Returns the linkages that are contained in this fragment */ diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java index 8d7f94c7810..501ad6fd756 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java @@ -12,6 +12,7 @@ * Andrew Ferguson (Symbian) * Anton Leherbauer (Wind River Systems) * Sergey Prigogin (Google) + * Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion) *******************************************************************************/ package org.eclipse.cdt.internal.core.pdom; @@ -694,7 +695,8 @@ public class PDOM extends PlatformObject implements IPDOM { char[][] simpleNames= extractSimpleNames(patterns); if (simpleNames != null && simpleNames.length == 1) { return findMacroContainers(simpleNames[0], false, caseSensitive, filter, monitor); - } + } + char[] prefix= extractPrefix(patterns); if (prefix != null) { return findMacroContainers(prefix, true, caseSensitive, filter, monitor); @@ -734,7 +736,7 @@ public class PDOM extends PlatformObject implements IPDOM { nodes.add(linkage); for (int i=0; i < names.length-1; i++) { char[] name= names[i]; - NamedNodeCollector collector= new NamedNodeCollector(linkage, name, false, caseSensitive); + NamedNodeCollector collector= new NamedNodeCollector(linkage, name, false, false, caseSensitive); for (Iterator in = nodes.iterator(); in.hasNext();) { PDOMNode node= in.next(); node.accept(collector); @@ -743,7 +745,7 @@ public class PDOM extends PlatformObject implements IPDOM { nodes.addAll(Arrays.asList(collector.getNodes())); } char[] name= names[names.length-1]; - BindingCollector collector= new BindingCollector(linkage, name, filter, false, caseSensitive); + BindingCollector collector= new BindingCollector(linkage, name, filter, false, false, caseSensitive); for (Iterator in = nodes.iterator(); in.hasNext();) { PDOMNode node= in.next(); node.accept(collector); @@ -1071,13 +1073,21 @@ public class PDOM extends PlatformObject implements IPDOM { public IIndexFragmentBinding[] findBindingsForPrefix(char[] prefix, boolean filescope, IndexFilter filter, IProgressMonitor monitor) throws CoreException { return findBindingsForPrefix(prefix, filescope, false, filter, monitor); } - + public IIndexFragmentBinding[] findBindingsForPrefix(char[] prefix, boolean filescope, boolean caseSensitive, IndexFilter filter, IProgressMonitor monitor) throws CoreException { + return findBindingsForPrefixOrContentAssist(prefix, filescope, false, caseSensitive, filter, monitor); + } + + public IIndexFragmentBinding[] findBindingsForContentAssist(char[] prefix, boolean filescope, IndexFilter filter, IProgressMonitor monitor) throws CoreException { + return findBindingsForPrefixOrContentAssist(prefix, filescope, true, false, filter, monitor); + } + + private IIndexFragmentBinding[] findBindingsForPrefixOrContentAssist(char[] prefix, boolean filescope, boolean isContentAssist, boolean caseSensitive, IndexFilter filter, IProgressMonitor monitor) throws CoreException { ArrayList result= new ArrayList(); for (PDOMLinkage linkage : getLinkageList()) { if (filter.acceptLinkage(linkage)) { PDOMBinding[] bindings; - BindingCollector visitor = new BindingCollector(linkage, prefix, filter, true, caseSensitive); + BindingCollector visitor = new BindingCollector(linkage, prefix, filter, !isContentAssist, isContentAssist, caseSensitive); visitor.setMonitor(monitor); try { linkage.accept(visitor); @@ -1117,7 +1127,7 @@ public class PDOM extends PlatformObject implements IPDOM { } if (!isCaseSensitive || !filescope) { - BindingCollector visitor= new BindingCollector(linkage, name, filter, false, isCaseSensitive); + BindingCollector visitor= new BindingCollector(linkage, name, filter, false, false, isCaseSensitive); visitor.setMonitor(monitor); if (!isCaseSensitive) @@ -1146,7 +1156,7 @@ public class PDOM extends PlatformObject implements IPDOM { try { for (PDOMLinkage linkage : getLinkageList()) { if (filter.acceptLinkage(linkage)) { - MacroContainerCollector visitor = new MacroContainerCollector(linkage, prefix, isPrefix, isCaseSensitive); + MacroContainerCollector visitor = new MacroContainerCollector(linkage, prefix, isPrefix, false, isCaseSensitive); visitor.setMonitor(monitor); linkage.getMacroIndex().accept(visitor); result.addAll(visitor.getMacroList()); @@ -1157,13 +1167,13 @@ public class PDOM extends PlatformObject implements IPDOM { } return result.toArray(new IIndexFragmentBinding[result.size()]); } - + public IIndexMacro[] findMacros(char[] prefix, boolean isPrefix, boolean isCaseSensitive, IndexFilter filter, IProgressMonitor monitor) throws CoreException { ArrayList result= new ArrayList(); try { for (PDOMLinkage linkage : getLinkageList()) { if (filter.acceptLinkage(linkage)) { - MacroContainerCollector visitor = new MacroContainerCollector(linkage, prefix, isPrefix, isCaseSensitive); + MacroContainerCollector visitor = new MacroContainerCollector(linkage, prefix, isPrefix, false, isCaseSensitive); visitor.setMonitor(monitor); linkage.getMacroIndex().accept(visitor); for (PDOMMacroContainer mcont : visitor.getMacroList()) { @@ -1175,7 +1185,7 @@ public class PDOM extends PlatformObject implements IPDOM { } return result.toArray(new IIndexMacro[result.size()]); } - + public String getProperty(String propertyName) throws CoreException { if (IIndexFragment.PROPERTY_FRAGMENT_FORMAT_ID.equals(propertyName)) { return FRAGMENT_PROPERTY_VALUE_FORMAT_ID; @@ -1393,7 +1403,7 @@ public class PDOM extends PlatformObject implements IPDOM { }; } if (filter != null) { - BindingCollector collector= new BindingCollector(cpp, binding.getNameCharArray(), filter, false, true); + BindingCollector collector= new BindingCollector(cpp, binding.getNameCharArray(), filter, false, false, true); cpp.accept(collector); return collector.getBindings(); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOMProxy.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOMProxy.java index a7b354cd243..89b0b1f9970 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOMProxy.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOMProxy.java @@ -8,6 +8,7 @@ * Contributors: * Markus Schorn - initial API and implementation * Sergey Prigogin (Google) + * Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion) *******************************************************************************/ package org.eclipse.cdt.internal.core.pdom; @@ -114,6 +115,14 @@ public class PDOMProxy implements IPDOM { return IIndexFragmentBinding.EMPTY_INDEX_BINDING_ARRAY; } + public synchronized IIndexFragmentBinding[] findBindingsForContentAssist(char[] prefix, boolean filescope, + IndexFilter filter, IProgressMonitor monitor) throws CoreException { + if (fDelegate != null) + return fDelegate.findBindingsForContentAssist(prefix, filescope, filter, monitor); + + return IIndexFragmentBinding.EMPTY_INDEX_BINDING_ARRAY; + } + public synchronized IIndexFragmentInclude[] findIncludedBy(IIndexFragmentFile file) throws CoreException { if (fDelegate != null) return fDelegate.findIncludedBy(file); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/BindingCollector.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/BindingCollector.java index 5aa74e415d6..8dd61c7552d 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/BindingCollector.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/BindingCollector.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2010 QNX Software Systems and others. + * Copyright (c) 2006, 2011 QNX Software Systems and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -9,6 +9,7 @@ * QNX - Initial API and implementation * Markus Schorn (Wind River Systems) * Andrew Ferguson (Symbian) + * Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion) *******************************************************************************/ package org.eclipse.cdt.internal.core.pdom.dom; @@ -32,15 +33,28 @@ public final class BindingCollector extends NamedNodeCollector { * Collects all bindings with given name. */ public BindingCollector(PDOMLinkage linkage, char[] name) { - this(linkage, name, null, false, true); + this(linkage, name, null, false, false, true); } - + /** - * Collects all bindings with given name, passing the filter. If prefixLookup is set to - * true a binding is considered if its name starts with the given prefix. + * Collects all bindings with given name, passing the filter. + * + * @param linkage + * @param name + * @param filter + * @param prefixLookup + * If set to true a binding is considered if its name starts with the given prefix + * Otherwise, the binding will only be considered if its name matches exactly. This parameter + * is ignored if contentAssistLookup is true. + * @param contentAssistLookup + * If set to true a binding is considered if its names matches according to the + * current content assist matching rules. + * @param caseSensitive + * Ignored if contentAssistLookup is true. */ - public BindingCollector(PDOMLinkage linkage, char[] name, IndexFilter filter, boolean prefixLookup, boolean caseSensitive) { - super(linkage, name, prefixLookup, caseSensitive); + public BindingCollector(PDOMLinkage linkage, char[] name, IndexFilter filter, boolean prefixLookup, + boolean contentAssistLookup, boolean caseSensitive) { + super(linkage, name, prefixLookup, contentAssistLookup, caseSensitive); this.filter= filter; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/MacroContainerCollector.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/MacroContainerCollector.java index e1173b5a634..3e46d0d63c8 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/MacroContainerCollector.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/MacroContainerCollector.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2009 Wind River Systems, Inc. and others. + * Copyright (c) 2007, 2011 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 @@ -7,12 +7,15 @@ * * Contributors: * Markus Schorn (Wind River Systems) + * Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion) *******************************************************************************/ package org.eclipse.cdt.internal.core.pdom.dom; import java.util.ArrayList; import java.util.List; +import org.eclipse.cdt.core.parser.util.ContentAssistMatcherFactory; +import org.eclipse.cdt.core.parser.util.IContentAssistMatcher; import org.eclipse.cdt.internal.core.pdom.db.IBTreeVisitor; import org.eclipse.cdt.internal.core.pdom.db.IString; import org.eclipse.core.runtime.CoreException; @@ -25,24 +28,47 @@ import org.eclipse.core.runtime.OperationCanceledException; */ public final class MacroContainerCollector implements IBTreeVisitor { private final PDOMLinkage linkage; - private final char[] name; + private final char[] matchChars; private final boolean prefixLookup; + private final IContentAssistMatcher contentAssistMatcher; private final boolean caseSensitive; private IProgressMonitor monitor= null; private int monitorCheckCounter= 0; private List macros = new ArrayList(); - + /** * Collects all nodes with given name, passing the filter. If prefixLookup is set to * true a binding is considered if its name starts with the given prefix. + * + * @param linkage + * @param name + * @param prefixLookup + * If set to true a binding is considered if its name starts with the given prefix + * Otherwise, the binding will only be considered if its name matches exactly. This parameter + * is ignored if contentAssistLookup is true. + * @param contentAssistLookup + * If set to true a binding is considered if its names matches according to the + * current content assist matching rules. + * @param caseSensitive + * Ignored if contentAssistLookup is true. */ - public MacroContainerCollector(PDOMLinkage linkage, char[] name, boolean prefixLookup, boolean caseSensitive) { - this.name= name; + public MacroContainerCollector(PDOMLinkage linkage, char[] name, boolean prefixLookup, + boolean contentAssistLookup, boolean caseSensitive) { + if (contentAssistLookup) { + IContentAssistMatcher matcher = ContentAssistMatcherFactory.getInstance().createMatcher(name); + this.contentAssistMatcher = matcher.matchRequiredAfterBinarySearch() ? matcher : null; + this.matchChars = matcher.getPrefixForBinarySearch(); + this.prefixLookup= true; + this.caseSensitive= false; + } else { + this.contentAssistMatcher = null; + this.matchChars = name; + this.prefixLookup= prefixLookup; + this.caseSensitive= caseSensitive; + } this.linkage= linkage; - this.prefixLookup= prefixLookup; - this.caseSensitive= caseSensitive; } /** @@ -63,17 +89,16 @@ public final class MacroContainerCollector implements IBTreeVisitor { private int compare(IString rhsName) throws CoreException { int cmp; if (prefixLookup) { - cmp= rhsName.comparePrefix(name, false); + cmp= rhsName.comparePrefix(matchChars, false); if(caseSensitive) { - cmp= cmp==0 ? rhsName.comparePrefix(name, true) : cmp; + cmp= cmp==0 ? rhsName.comparePrefix(matchChars, true) : cmp; } - return cmp; } else { if(caseSensitive) { - cmp= rhsName.compareCompatibleWithIgnoreCase(name); + cmp= rhsName.compareCompatibleWithIgnoreCase(matchChars); } else { - cmp= rhsName.compare(name, false); + cmp= rhsName.compare(matchChars, false); } } return cmp; @@ -85,8 +110,16 @@ public final class MacroContainerCollector implements IBTreeVisitor { if (record == 0) return true; - - macros.add(new PDOMMacroContainer(linkage, record)); + + if (contentAssistMatcher != null) { + char[] nodeName = PDOMNamedNode.getDBName(linkage.getDB(), record).getChars(); + if (contentAssistMatcher.match(nodeName)) { + macros.add(new PDOMMacroContainer(linkage, record)); + } + } else { + macros.add(new PDOMMacroContainer(linkage, record)); + } + return true; // look for more } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/NamedNodeCollector.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/NamedNodeCollector.java index 99c33ed6b44..ee0a8f84394 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/NamedNodeCollector.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/NamedNodeCollector.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2009 Wind River Systems, Inc. and others. + * Copyright (c) 2007, 2011 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 @@ -7,6 +7,7 @@ * * Contributors: * Markus Schorn - initial API and implementation + * Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion) *******************************************************************************/ package org.eclipse.cdt.internal.core.pdom.dom; @@ -15,6 +16,8 @@ import java.util.List; import org.eclipse.cdt.core.dom.IPDOMNode; import org.eclipse.cdt.core.dom.IPDOMVisitor; +import org.eclipse.cdt.core.parser.util.ContentAssistMatcherFactory; +import org.eclipse.cdt.core.parser.util.IContentAssistMatcher; import org.eclipse.cdt.internal.core.pdom.db.IBTreeVisitor; import org.eclipse.cdt.internal.core.pdom.db.IString; import org.eclipse.core.runtime.CoreException; @@ -26,9 +29,11 @@ import org.eclipse.core.runtime.OperationCanceledException; * @since 4.0 */ public class NamedNodeCollector implements IBTreeVisitor, IPDOMVisitor { + private final PDOMLinkage linkage; - private final char[] name; + private final char[] matchChars; private final boolean prefixLookup; + private final IContentAssistMatcher contentAssistMatcher; private final boolean caseSensitive; private IProgressMonitor monitor= null; private int monitorCheckCounter= 0; @@ -39,18 +44,39 @@ public class NamedNodeCollector implements IBTreeVisitor, IPDOMVisitor { * Collects all nodes with given name. */ public NamedNodeCollector(PDOMLinkage linkage, char[] name) { - this(linkage, name, false, true); + this(linkage, name, false, false, true); } - + /** - * Collects all nodes with given name, passing the filter. If prefixLookup is set to - * true a binding is considered if its name starts with the given prefix. + * Collects all nodes with given name, passing the filter. + * + * @param linkage + * @param name + * @param prefixLookup + * If set to true a binding is considered if its name starts with the given prefix + * Otherwise, the binding will only be considered if its name matches exactly. This parameter + * is ignored if contentAssistLookup is true. + * @param contentAssistLookup + * If set to true a binding is considered if its names matches according to the + * current content assist matching rules. + * @param caseSensitive + * Ignored if contentAssistLookup is true. */ - public NamedNodeCollector(PDOMLinkage linkage, char[] name, boolean prefixLookup, boolean caseSensitive) { - this.name= name; + public NamedNodeCollector(PDOMLinkage linkage, char[] name, boolean prefixLookup, + boolean contentAssistLookup, boolean caseSensitive) { this.linkage= linkage; - this.prefixLookup= prefixLookup; - this.caseSensitive= caseSensitive; + if (contentAssistLookup) { + IContentAssistMatcher matcher = ContentAssistMatcherFactory.getInstance().createMatcher(name); + this.contentAssistMatcher = matcher.matchRequiredAfterBinarySearch() ? matcher : null; + this.matchChars = matcher.getPrefixForBinarySearch(); + this.prefixLookup= true; + this.caseSensitive= false; + } else { + this.contentAssistMatcher = null; + this.matchChars = name; + this.prefixLookup= prefixLookup; + this.caseSensitive= caseSensitive; + } } /** @@ -71,17 +97,16 @@ public class NamedNodeCollector implements IBTreeVisitor, IPDOMVisitor { private int compare(IString rhsName) throws CoreException { int cmp; if (prefixLookup) { - cmp= rhsName.comparePrefix(name, false); + cmp= rhsName.comparePrefix(matchChars, false); if(caseSensitive) { - cmp= cmp==0 ? rhsName.comparePrefix(name, true) : cmp; + cmp= cmp==0 ? rhsName.comparePrefix(matchChars, true) : cmp; } - return cmp; } else { if(caseSensitive) { - cmp= rhsName.compareCompatibleWithIgnoreCase(name); + cmp= rhsName.compareCompatibleWithIgnoreCase(matchChars); } else { - cmp= rhsName.compare(name, false); + cmp= rhsName.compare(matchChars, false); } } return cmp; @@ -106,7 +131,9 @@ public class NamedNodeCollector implements IBTreeVisitor, IPDOMVisitor { * @throws CoreException */ protected boolean addNode(PDOMNamedNode node) throws CoreException { - nodes.add(node); + if ((contentAssistMatcher == null) || contentAssistMatcher.match(node.getDBName().getChars())) { + nodes.add(node); + } return true; // look for more } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMLinkage.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMLinkage.java index 52ec141fe21..6df8cd0297d 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMLinkage.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMLinkage.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2010 QNX Software Systems and others. + * Copyright (c) 2005, 2011 QNX Software Systems and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -10,6 +10,7 @@ * Markus Schorn (Wind River Systems) * IBM Corporation * Andrew Ferguson (Symbian) + * Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion) *******************************************************************************/ package org.eclipse.cdt.internal.core.pdom.dom; @@ -399,7 +400,7 @@ public abstract class PDOMLinkage extends PDOMNamedNode implements IIndexLinkage return result; } - BindingCollector visitor = new BindingCollector(this, name, null, false, true); + BindingCollector visitor = new BindingCollector(this, name, null, false, false, true); visitor.setMonitor(monitor); getIndex().accept(visitor); PDOMBinding[] result= visitor.getBindings(); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPClassScope.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPClassScope.java index d4c75b5cc22..8ded17fb4c5 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPClassScope.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPClassScope.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2010 QNX Software Systems and others. + * Copyright (c) 2005, 2011 QNX Software Systems and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -11,6 +11,7 @@ * Andrew Ferguson (Symbian) * Bryan Wilkinson (QNX) * Sergey Prigogin (Google) + * Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion) *******************************************************************************/ package org.eclipse.cdt.internal.core.pdom.dom.cpp; @@ -41,6 +42,7 @@ import org.eclipse.cdt.core.index.IndexFilter; import org.eclipse.cdt.core.parser.Keywords; import org.eclipse.cdt.core.parser.util.CharArrayMap; import org.eclipse.cdt.core.parser.util.CharArrayUtils; +import org.eclipse.cdt.core.parser.util.ContentAssistMatcherFactory; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassScope; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil; @@ -140,7 +142,7 @@ class PDOMCPPClassScope implements ICPPClassScope, IIndexScope { public IBinding[] getBindings(IASTName name, boolean resolve, boolean prefixLookup, IIndexFileSet fileSet) { try { if (name instanceof ICPPASTConversionName) { - BindingCollector visitor = new BindingCollector(fBinding.getLinkage(), Keywords.cOPERATOR, CONVERSION_FILTER, true, true); + BindingCollector visitor = new BindingCollector(fBinding.getLinkage(), Keywords.cOPERATOR, CONVERSION_FILTER, true, false, true); acceptViaCache(fBinding, visitor, true); return visitor.getBindings(); } @@ -157,8 +159,8 @@ class PDOMCPPClassScope implements ICPPClassScope, IIndexScope { } // prefix lookup - BindingCollector visitor = new BindingCollector(fBinding.getLinkage(), nameChars, IndexFilter.CPP_DECLARED_OR_IMPLICIT_NO_INSTANCE, prefixLookup, !prefixLookup); - if (CharArrayUtils.equals(fBinding.getNameCharArray(), 0, nameChars.length, nameChars, true)) { + BindingCollector visitor = new BindingCollector(fBinding.getLinkage(), nameChars, IndexFilter.CPP_DECLARED_OR_IMPLICIT_NO_INSTANCE, prefixLookup, prefixLookup, !prefixLookup); + if (ContentAssistMatcherFactory.getInstance().match(nameChars, fBinding.getNameCharArray())) { // add the class itself, constructors will be found during the visit visitor.visit((IPDOMNode) getClassNameBinding()); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPEnumScope.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPEnumScope.java index c9633d6b9e9..4267361435c 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPEnumScope.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPEnumScope.java @@ -7,6 +7,7 @@ * * Contributors: * Markus Schorn - initial API and implementation + * Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion) *******************************************************************************/ package org.eclipse.cdt.internal.core.pdom.dom.cpp; @@ -28,7 +29,8 @@ import org.eclipse.cdt.core.index.IIndexFileSet; import org.eclipse.cdt.core.index.IIndexName; import org.eclipse.cdt.core.index.IndexFilter; import org.eclipse.cdt.core.parser.util.CharArrayMap; -import org.eclipse.cdt.core.parser.util.CharArrayUtils; +import org.eclipse.cdt.core.parser.util.ContentAssistMatcherFactory; +import org.eclipse.cdt.core.parser.util.IContentAssistMatcher; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics; import org.eclipse.cdt.internal.core.index.IIndexScope; import org.eclipse.cdt.internal.core.pdom.PDOM; @@ -72,8 +74,9 @@ class PDOMCPPEnumScope implements ICPPScope, IIndexScope { if (prefixLookup) { final List result= new ArrayList(); final char[] nc= name.toCharArray(); + IContentAssistMatcher matcher = ContentAssistMatcherFactory.getInstance().createMatcher(nc); for (char[] key : map.keys()) { - if (CharArrayUtils.equals(key, 0, nc.length, nc, true)) { + if (matcher.match(key)) { result.add(map.get(key)); } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPNamespace.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPNamespace.java index 2ddf68de649..74420f77ad4 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPNamespace.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPNamespace.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2010 QNX Software Systems and others. + * Copyright (c) 2006, 2011 QNX Software Systems and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -10,6 +10,7 @@ * Markus Schorn (Wind River Systems) * Andrew Ferguson (Symbian) * Bryan Wilkinson (QNX) + * Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion) *******************************************************************************/ package org.eclipse.cdt.internal.core.pdom.dom.cpp; @@ -151,7 +152,7 @@ class PDOMCPPNamespace extends PDOMCPPBinding public IBinding[] find(String name) { try { BindingCollector visitor = new BindingCollector(getLinkage(), name.toCharArray(), - IndexFilter.CPP_DECLARED_OR_IMPLICIT_NO_INSTANCE, false, true); + IndexFilter.CPP_DECLARED_OR_IMPLICIT_NO_INSTANCE, false, false, true); getIndex().accept(visitor); return visitor.getBindings(); } catch (CoreException e) { @@ -182,7 +183,7 @@ class PDOMCPPNamespace extends PDOMCPPBinding result= getBindingsViaCache(name.getLookupKey()); } else { BindingCollector visitor= new BindingCollector(getLinkage(), name.getLookupKey(), - IndexFilter.CPP_DECLARED_OR_IMPLICIT_NO_INSTANCE, prefixLookup, !prefixLookup); + IndexFilter.CPP_DECLARED_OR_IMPLICIT_NO_INSTANCE, prefixLookup, prefixLookup, !prefixLookup); getIndex().accept(visitor); result = visitor.getBindings(); } @@ -203,7 +204,7 @@ class PDOMCPPNamespace extends PDOMCPPBinding return result; } BindingCollector visitor = new BindingCollector(getLinkage(), name, - IndexFilter.CPP_DECLARED_OR_IMPLICIT_NO_INSTANCE, false, true); + IndexFilter.CPP_DECLARED_OR_IMPLICIT_NO_INSTANCE, false, false, true); getIndex().accept(visitor); result = visitor.getBindings(); pdom.putCachedResult(key, result); diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CCorePlugin.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CCorePlugin.java index 206ed525c25..d3801b236df 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CCorePlugin.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CCorePlugin.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2010 IBM Corporation and others. + * Copyright (c) 2000, 2011 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 @@ -11,6 +11,7 @@ * Andrew Ferguson (Symbian) * Anton Leherbauer (Wind River Systems) * oyvind.harboe@zylin.com - http://bugs.eclipse.org/250638 + * Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion) *******************************************************************************/ package org.eclipse.cdt.core; @@ -32,6 +33,7 @@ import org.eclipse.cdt.core.model.ILanguage; import org.eclipse.cdt.core.model.ITranslationUnit; import org.eclipse.cdt.core.model.IWorkingCopy; import org.eclipse.cdt.core.parser.IScannerInfoProvider; +import org.eclipse.cdt.core.parser.util.ContentAssistMatcherFactory; import org.eclipse.cdt.core.resources.IConsole; import org.eclipse.cdt.core.resources.IPathEntryVariableManager; import org.eclipse.cdt.core.settings.model.ICConfigExtensionReference; @@ -294,7 +296,9 @@ public class CCorePlugin extends Plugin { fNewCProjectDescriptionManager.shutdown(); ResourceLookup.shutdown(); - + + ContentAssistMatcherFactory.shutdown(); + savePluginPreferences(); } finally { super.stop(context); diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CCorePreferenceConstants.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CCorePreferenceConstants.java index 31263d4fda9..605e7ed962e 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CCorePreferenceConstants.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CCorePreferenceConstants.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2010 QNX Software Systems and others. + * Copyright (c) 2000, 2011 QNX Software Systems and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -10,6 +10,7 @@ * Markus Schorn (Wind River Systems) * Sergey Prigogin (Google) * IBM Corporation + * Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion) *******************************************************************************/ package org.eclipse.cdt.core; @@ -163,4 +164,11 @@ public class CCorePreferenceConstants { * @since 5.3 */ public static final String PREF_BUILD_CONFIGS_RESOURCE_CHANGES = "build.proj.ref.configs.enabled"; //$NON-NLS-1$ + + /** + * Key for boolean preference telling whether camel case/underscore matches are to be shown by content assist features or not. + * + * @since 5.3 + */ + public static final String SHOW_CAMEL_CASE_MATCHES = "contentAssist.showCamelCaseMatches"; //$NON-NLS-1$ } diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/CCorePreferenceInitializer.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/CCorePreferenceInitializer.java index 9733cabde52..6f15162b886 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/CCorePreferenceInitializer.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/CCorePreferenceInitializer.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2010 QNX Software Systems and others. + * Copyright (c) 2000, 2011 QNX Software Systems and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -10,6 +10,7 @@ * Sergey Prigogin (Google) * Markus Schorn (Wind River Systems) * IBM Corporation + * Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion) *******************************************************************************/ package org.eclipse.cdt.internal.core; @@ -69,5 +70,8 @@ public class CCorePreferenceInitializer extends AbstractPreferenceInitializer { // indexer defaults IndexerPreferences.initializeDefaultPreferences(defaultPreferences); + + // content assist defaults + defaultPreferences.putBoolean(CCorePreferenceConstants.SHOW_CAMEL_CASE_MATCHES, true); } } 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 13fe0f2bbf0..31f1843c2e9 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 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2010 Wind River Systems, Inc. and others. + * Copyright (c) 2006, 2011 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 @@ -11,6 +11,7 @@ * Markus Schorn (Wind River Systems) * IBM Corporation * Sergey Prigogin (Google) + * Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion) *******************************************************************************/ package org.eclipse.cdt.ui.tests.text.contentassist2; @@ -300,7 +301,7 @@ public class CompletionTests extends AbstractContentAssistTest { //void f() {gC/*cursor*/ public void testGlobalVariables_GlobalScope() throws Exception { final String[] expected= { - "gC1", "gC2" + "gC1", "gC2", "gfC1(void)", "gfC2(void)" }; assertCompletionResults(fCursorOffset, expected, AbstractContentAssistTest.COMPARE_ID_STRINGS); } @@ -308,7 +309,7 @@ public class CompletionTests extends AbstractContentAssistTest { //void C1::f() {gC/*cursor*/ public void testGlobalVariables_MethodScope() throws Exception { final String[] expected= { - "gC1", "gC2" + "gC1", "gC2", "gfC1(void)", "gfC2(void)" }; assertCompletionResults(fCursorOffset, expected, AbstractContentAssistTest.COMPARE_ID_STRINGS); } @@ -1353,4 +1354,18 @@ public class CompletionTests extends AbstractContentAssistTest { final String[] expected= { "BaseMethod(void)" }; assertCompletionResults(fCursorOffset, expected, COMPARE_ID_STRINGS); } + + // #define fooBar + // #define foo_bar + // fB/*cursor*/ + public void testUserMacroSegmentMatch() throws Exception { + final String[] expected= { "fooBar", "foo_bar" }; + assertCompletionResults(fCursorOffset, expected, COMPARE_ID_STRINGS); + } + + // __bVA/*cursor*/ + public void testBuiltinMacroSegmentMatch() throws Exception { + final String[] expected= { "__builtin_va_arg(ap, type)" }; + assertCompletionResults(fCursorOffset, expected, COMPARE_ID_STRINGS); + } } \ No newline at end of file diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/CompletionTests_PlainC.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/CompletionTests_PlainC.java index 456ad0a8e94..d389711fc0f 100644 --- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/CompletionTests_PlainC.java +++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/CompletionTests_PlainC.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2010 Wind River Systems, Inc. and others. + * Copyright (c) 2007, 2011 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 @@ -9,6 +9,7 @@ * Anton Leherbauer (Wind River Systems) - initial API and implementation * Markus Schorn (Wind River Systems) * IBM Corporation + * Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion) *******************************************************************************/ package org.eclipse.cdt.ui.tests.text.contentassist2; @@ -594,7 +595,7 @@ public class CompletionTests_PlainC extends AbstractContentAssistTest { //void f() {gC/*cursor*/ public void testGlobalVariables_GlobalScope() throws Exception { final String[] expected= { - "gC1", "gC2" + "gC1", "gC2", "gfC1(void)", "gfC2(void)" }; assertCompletionResults(expected); } @@ -604,7 +605,7 @@ public class CompletionTests_PlainC extends AbstractContentAssistTest { //void foo() {gC/*cursor*/ public void testGlobalVariables_FunctionScope() throws Exception { final String[] expected= { - "gC1", "gC2" + "gC1", "gC2", "gfC1(void)", "gfC2(void)" }; assertCompletionResults(expected); } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/AbstractMixedPreferencePage.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/AbstractMixedPreferencePage.java new file mode 100644 index 00000000000..c531330202b --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/AbstractMixedPreferencePage.java @@ -0,0 +1,103 @@ +/******************************************************************************* + * Copyright (c) 2011 Jens Elmenthaler 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: + * Jens Elmenthaler - initial API and implementation + * (http://bugs.eclipse.org/173458, camel case completion) + *******************************************************************************/ +package org.eclipse.cdt.internal.ui.preferences; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.eclipse.core.runtime.preferences.InstanceScope; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.ui.preferences.ScopedPreferenceStore; + +import org.eclipse.cdt.core.CCorePlugin; + +/** + * A preference that on preference from the UI plugin, as well the CDT core. + * + * Currently only supporting boolean preferences. + */ +public abstract class AbstractMixedPreferencePage extends AbstractPreferencePage { + + protected OverlayPreferenceStore corePrefsOverlayStore; + + private Map corePrefsCheckBoxes = new HashMap(); + private SelectionListener corePrefsCheckBoxListener = new SelectionListener() { + public void widgetDefaultSelected(SelectionEvent e) { + } + + public void widgetSelected(SelectionEvent e) { + Button button = (Button) e.widget; + corePrefsOverlayStore.setValue(corePrefsCheckBoxes.get(button), button.getSelection()); + } + }; + + public AbstractMixedPreferencePage() { + corePrefsOverlayStore = new OverlayPreferenceStore(new ScopedPreferenceStore(InstanceScope.INSTANCE, + CCorePlugin.PLUGIN_ID), createCorePrefsOverlayStoreKeys()); + } + + protected Button addCorePrefsCheckBox(Composite parent, String label, String key, int indentation) { + Button checkBox = new Button(parent, SWT.CHECK); + checkBox.setText(label); + + GridData gd = new GridData(GridData.FILL_HORIZONTAL); + gd.horizontalIndent = indentation; + gd.horizontalSpan = 2; + checkBox.setLayoutData(gd); + checkBox.addSelectionListener(corePrefsCheckBoxListener); + + corePrefsCheckBoxes.put(checkBox, key); + + return checkBox; + } + + protected abstract OverlayPreferenceStore.OverlayKey[] createCorePrefsOverlayStoreKeys(); + + @Override + protected void initializeFields() { + super.initializeFields(); + + Iterator