From bb5cead81a481be877fb0e9ea0711b36b82effe0 Mon Sep 17 00:00:00 2001 From: Anton Leherbauer Date: Wed, 5 Mar 2008 13:42:02 +0000 Subject: [PATCH] Minor improvements for content assist in preprocessor directives --- .../text/contentassist2/CompletionTests.java | 20 ++- .../internal/ui/text/FastCPartitioner.java | 8 +- .../DOMCompletionProposalComputer.java | 60 ++++++-- .../KeywordCompletionProposalComputer.java | 141 +++++++++++++----- 4 files changed, 172 insertions(+), 57 deletions(-) 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 f70cc8a3cdf..1ace88ff865 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 @@ -695,7 +695,25 @@ public class CompletionTests extends AbstractContentAssistTest { //#i/*cursor*/ public void testCompletePreprocessorDirective() throws Exception { final String[] expected= { - "#if", "#ifdef", "#ifndef", "#include" + "#if ", "#ifdef ", "#ifndef ", "#include " + }; + assertCompletionResults(fCursorOffset, expected, + AbstractContentAssistTest.COMPARE_ID_STRINGS); + } + + //# d/*cursor*/ + public void testCompletePreprocessorDirective2() throws Exception { + final String[] expected= { + "define " + }; + assertCompletionResults(fCursorOffset, expected, + AbstractContentAssistTest.COMPARE_REP_STRINGS); + } + + //# if d/*cursor*/ + public void testCompletePreprocessorDirective3() throws Exception { + final String[] expected= { + "defined" }; assertCompletionResults(fCursorOffset, expected, AbstractContentAssistTest.COMPARE_ID_STRINGS); diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/FastCPartitioner.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/FastCPartitioner.java index 653d6e0ab1d..9274c99b1be 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/FastCPartitioner.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/FastCPartitioner.java @@ -42,7 +42,7 @@ public class FastCPartitioner extends FastPartitioner { if (!fDocument.get(offset - 2, 2).equals("*/")) { //$NON-NLS-1$ return region; } - } else if (ICPartitions.C_SINGLE_LINE_COMMENT.equals(region .getType())) { + } else if (ICPartitions.C_SINGLE_LINE_COMMENT.equals(region.getType())) { if (fDocument.getChar(offset - 1) != '\n') { return region; } @@ -50,7 +50,11 @@ public class FastCPartitioner extends FastPartitioner { if (!fDocument.get(offset - 2, 2).equals("*/")) { //$NON-NLS-1$ return region; } - } else if (ICPartitions.C_SINGLE_LINE_DOC_COMMENT.equals(region .getType())) { + } else if (ICPartitions.C_SINGLE_LINE_DOC_COMMENT.equals(region.getType())) { + if (fDocument.getChar(offset - 1) != '\n') { + return region; + } + } else if (ICPartitions.C_PREPROCESSOR.equals(region.getType())) { if (fDocument.getChar(offset - 1) != '\n') { return region; } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/DOMCompletionProposalComputer.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/DOMCompletionProposalComputer.java index 3afb07e8582..7dbdbd445b1 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/DOMCompletionProposalComputer.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/DOMCompletionProposalComputer.java @@ -18,6 +18,7 @@ import java.util.List; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.ITypedRegion; import org.eclipse.jface.text.TextUtilities; import org.eclipse.swt.graphics.Image; @@ -88,8 +89,17 @@ public class DOMCompletionProposalComputer extends ParsingBasedProposalComputer List proposals = new ArrayList(); if(inPreprocessorDirective(context)) { - // add only macros - addMacroProposals(context, prefix, proposals); + if (!inPreprocessorKeyword(context)) { + // add only macros + if (prefix.length() == 0) { + try { + prefix= context.computeIdentifierPrefix().toString(); + } catch (BadLocationException exc) { + CUIPlugin.getDefault().log(exc); + } + } + addMacroProposals(context, prefix, proposals); + } } else { boolean handleMacros= false; IASTName[] names = completionNode.getNames(); @@ -124,22 +134,46 @@ public class DOMCompletionProposalComputer extends ParsingBasedProposalComputer } /** - * Check if given offset is inside a preprocessor directive. + * Test whether the invocation offset is inside or before the preprocessor directive keyword. * - * @param doc the document - * @param offset the offset to check - * @return true if offset is inside a preprocessor directive + * @param context the invocation context + * @return true if the invocation offset is inside or before the directive keyword + */ + private boolean inPreprocessorKeyword(CContentAssistInvocationContext context) { + IDocument doc = context.getDocument(); + int offset = context.getInvocationOffset(); + + try { + final ITypedRegion partition= TextUtilities.getPartition(doc, ICPartitions.C_PARTITIONING, offset, true); + if (ICPartitions.C_PREPROCESSOR.equals(partition.getType())) { + String ppPrefix= doc.get(partition.getOffset(), offset - partition.getOffset()); + if (ppPrefix.matches("\\s*#\\s*\\w*")) { //$NON-NLS-1$ + // we are inside the directive keyword + return true; + } + } + + } catch (BadLocationException exc) { + } + return false; + } + + /** + * Check if the invocation offset is inside a preprocessor directive. + * + * @param context the content asist invocation context + * @return true if invocation offset is inside a preprocessor directive */ private boolean inPreprocessorDirective(CContentAssistInvocationContext context) { - IDocument doc = context.getViewer().getDocument(); - int offset = context.getParseOffset(); + IDocument doc = context.getDocument(); + int offset = context.getInvocationOffset(); - if (offset > 0 && offset == doc.getLength()) { - --offset; - } try { - return ICPartitions.C_PREPROCESSOR - .equals(TextUtilities.getContentType(doc, ICPartitions.C_PARTITIONING, offset, false)); + final ITypedRegion partition= TextUtilities.getPartition(doc, ICPartitions.C_PARTITIONING, offset, true); + if (ICPartitions.C_PREPROCESSOR.equals(partition.getType())) { + return true; + } + } catch (BadLocationException exc) { } return false; diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/KeywordCompletionProposalComputer.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/KeywordCompletionProposalComputer.java index 8c29c9d52fa..61713ca00ca 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/KeywordCompletionProposalComputer.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/KeywordCompletionProposalComputer.java @@ -1,12 +1,13 @@ /******************************************************************************* - * Copyright (c) 2007 QNX Software Systems and others. + * Copyright (c) 2007, 2008 QNX Software Systems and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * Bryan Wilkinson (QNX) - Initial API and implementation + * Bryan Wilkinson (QNX) - Initial API and implementation + * Anton Leherbauer (Wind River Systems) *******************************************************************************/ package org.eclipse.cdt.internal.ui.text.contentassist; @@ -18,6 +19,7 @@ import org.eclipse.core.runtime.CoreException; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.ITypedRegion; import org.eclipse.jface.text.TextUtilities; import org.eclipse.swt.graphics.Image; @@ -35,21 +37,53 @@ import org.eclipse.cdt.internal.ui.viewsupport.CElementImageProvider; public class KeywordCompletionProposalComputer extends ParsingBasedProposalComputer implements ICompletionProposalComputer { - protected List computeCompletionProposals( + protected List computeCompletionProposals( CContentAssistInvocationContext context, IASTCompletionNode completionNode, String prefix) throws CoreException { + if (prefix.length() == 0) { + try { + prefix= context.computeIdentifierPrefix().toString(); + } catch (BadLocationException exc) { + CUIPlugin.getDefault().log(exc); + } + } // No prefix, no completions if (prefix.length() == 0 || context.isContextInformationStyle()) - return Collections.EMPTY_LIST; + return Collections.emptyList(); String[] keywords; - if(inPreprocessorDirective(context.getDocument(), context.getInvocationOffset())) { + List proposals = new ArrayList(); + + if (inPreprocessorDirective(context)) { + // TODO split this into a separate proposal computer? + boolean needDirectiveKeyword= inPreprocessorKeyword(context); keywords= preprocessorKeywords; + + // add matching preprocessor keyword proposals + ImageDescriptor imagedesc = CElementImageProvider.getKeywordImageDescriptor(); + Image image = imagedesc != null ? CUIPlugin.getImageDescriptorRegistry().get(imagedesc) : null; + for (int i = 0; i < keywords.length; ++i) { + String repString= keywords[i]; + if (repString.startsWith(prefix)) { + int repLength = prefix.length(); + int repOffset = context.getInvocationOffset() - repLength; + if (prefix.charAt(0) == '#') { + // strip leading '#' from replacement + repLength--; + repOffset++; + repString= repString.substring(1); + } else if (needDirectiveKeyword) { + continue; + } + proposals.add(new CCompletionProposal(repString, repOffset, + repLength, image, keywords[i], 1, context.getViewer())); + } + } } else { if (!isValidContext(completionNode)) - return Collections.EMPTY_LIST; + return Collections.emptyList(); ITranslationUnit tu = context.getTranslationUnit(); @@ -57,21 +91,18 @@ public class KeywordCompletionProposalComputer extends ParsingBasedProposalCompu if (tu != null && tu.isCLanguage()) keywords = ckeywords; + // add matching keyword proposals + ImageDescriptor imagedesc = CElementImageProvider.getKeywordImageDescriptor(); + Image image = imagedesc != null ? CUIPlugin.getImageDescriptorRegistry().get(imagedesc) : null; + for (int i = 0; i < keywords.length; ++i) { + if (keywords[i].startsWith(prefix)) { + int repLength = prefix.length(); + int repOffset = context.getInvocationOffset() - repLength; + proposals.add(new CCompletionProposal(keywords[i], repOffset, + repLength, image, keywords[i], 1, context.getViewer())); + } + } } - - List proposals = new ArrayList(); - - // add matching keyword proposals - ImageDescriptor imagedesc = CElementImageProvider.getKeywordImageDescriptor(); - Image image = imagedesc != null ? CUIPlugin.getImageDescriptorRegistry().get(imagedesc) : null; - for (int i = 0; i < keywords.length; ++i) { - if (keywords[i].startsWith(prefix)) { - int repLength = prefix.length(); - int repOffset = context.getInvocationOffset() - repLength; - proposals.add(new CCompletionProposal(keywords[i], repOffset, - repLength, image, keywords[i], 1, context.getViewer())); - } - } return proposals; } @@ -100,26 +131,53 @@ public class KeywordCompletionProposalComputer extends ParsingBasedProposalCompu return false; } - + /** - * Check if given offset is inside a preprocessor directive. + * Test whether the invocation offset is inside or before the preprocessor directive keyword. * - * @param doc the document - * @param offset the offset to check - * @return true if offset is inside a preprocessor directive + * @param context the invocation context + * @return true if the invocation offset is inside or before the directive keyword */ - private boolean inPreprocessorDirective(IDocument doc, int offset) { - if (offset > 0 && offset == doc.getLength()) { - --offset; - } + private boolean inPreprocessorKeyword(CContentAssistInvocationContext context) { + IDocument doc = context.getDocument(); + int offset = context.getInvocationOffset(); + try { - return ICPartitions.C_PREPROCESSOR - .equals(TextUtilities.getContentType(doc, ICPartitions.C_PARTITIONING, offset, false)); + final ITypedRegion partition= TextUtilities.getPartition(doc, ICPartitions.C_PARTITIONING, offset, true); + if (ICPartitions.C_PREPROCESSOR.equals(partition.getType())) { + String ppPrefix= doc.get(partition.getOffset(), offset - partition.getOffset()); + if (ppPrefix.matches("\\s*#\\s*\\w*")) { //$NON-NLS-1$ + // we are inside the directive keyword + return true; + } + } + } catch (BadLocationException exc) { } return false; } - + + /** + * Check if the invocation offset is inside a preprocessor directive. + * + * @param context the content asist invocation context + * @return true if invocation offset is inside a preprocessor directive + */ + private boolean inPreprocessorDirective(CContentAssistInvocationContext context) { + IDocument doc = context.getDocument(); + int offset = context.getInvocationOffset(); + + try { + final ITypedRegion partition= TextUtilities.getPartition(doc, ICPartitions.C_PARTITIONING, offset, true); + if (ICPartitions.C_PREPROCESSOR.equals(partition.getType())) { + return true; + } + + } catch (BadLocationException exc) { + } + return false; + } + // These are the keywords we complete // We only do the ones that are >= 5 characters long private static String [] ckeywords = { @@ -199,16 +257,17 @@ public class KeywordCompletionProposalComputer extends ParsingBasedProposalCompu }; private static String [] preprocessorKeywords = { - Directives.POUND_DEFINE, - Directives.POUND_ELIF, + Directives.POUND_DEFINE + ' ', + Directives.POUND_ELIF + ' ', Directives.POUND_ELSE, Directives.POUND_ENDIF, - Directives.POUND_ERROR, - Directives.POUND_IF, - Directives.POUND_IFDEF, - Directives.POUND_IFNDEF, - Directives.POUND_INCLUDE, - Directives.POUND_PRAGMA, - Directives.POUND_UNDEF, + Directives.POUND_ERROR + ' ', + Directives.POUND_IF + ' ', + Directives.POUND_IFDEF + ' ', + Directives.POUND_IFNDEF + ' ', + Directives.POUND_INCLUDE + ' ', + Directives.POUND_PRAGMA + ' ', + Directives.POUND_UNDEF + ' ', + "defined" //$NON-NLS-1$ }; }