com.google.dart.tools.ui.internal.text.completion.DartMethodCompletionProposal.java Source code

Java tutorial

Introduction

Here is the source code for com.google.dart.tools.ui.internal.text.completion.DartMethodCompletionProposal.java

Source

/*
 * Copyright (c) 2012, the Dart project authors.
 * 
 * Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 * 
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
package com.google.dart.tools.ui.internal.text.completion;

import com.google.dart.tools.core.completion.CompletionProposal;
import com.google.dart.tools.core.model.DartProject;
import com.google.dart.tools.ui.DartElementLabels;
import com.google.dart.tools.ui.DartToolsPlugin;
import com.google.dart.tools.ui.PreferenceConstants;
import com.google.dart.tools.ui.internal.text.dart.ProposalContextInformation;
import com.google.dart.tools.ui.text.dart.DartContentAssistInvocationContext;
import com.google.dart.tools.ui.text.editor.tmp.Signature;

import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.contentassist.IContextInformation;
import org.eclipse.osgi.util.TextProcessor;

public class DartMethodCompletionProposal extends LazyDartCompletionProposal {
    /** Triggers for method proposals without parameters. Do not modify. */
    protected final static char[] METHOD_TRIGGERS = new char[] { ';', ',', '.', '\t', '[' };
    /** Triggers for method proposals. Do not modify. */
    protected final static char[] METHOD_WITH_ARGUMENTS_TRIGGERS = new char[] { '(', '-', ' ' };
    /** Triggers for method name proposals (static imports). Do not modify. */
    protected final static char[] METHOD_NAME_TRIGGERS = new char[] { ';' };

    private boolean fHasParameters;
    private boolean fHasParametersComputed = false;
    private FormatterPrefs fFormatterPrefs;

    public DartMethodCompletionProposal(CompletionProposal proposal, DartContentAssistInvocationContext context) {
        super(proposal, context);
    }

    @Override
    public void apply(IDocument document, char trigger, int offset) {
        if (trigger == ' ' || trigger == '(') {
            trigger = '\0';
        }
        super.apply(document, trigger, offset);
        if (needsLinkedMode()) {
            setUpLinkedMode(document, ')');
        }
    }

    @Override
    public int getPrefixCompletionStart(IDocument document, int completionOffset) {
        if (fProposal.getKind() == CompletionProposal.CONSTRUCTOR_INVOCATION) {
            return fProposal.getRequiredProposals()[0].getReplaceStart();
        }
        return super.getPrefixCompletionStart(document, completionOffset);
    }

    @Override
    public CharSequence getPrefixCompletionText(IDocument document, int completionOffset) {
        if (hasArgumentList() || fProposal.getKind() == CompletionProposal.CONSTRUCTOR_INVOCATION) {
            String completion = String.valueOf(fProposal.getName());
            if (isCamelCaseMatching()) {
                String prefix = getPrefix(document, completionOffset);
                return getCamelCaseCompound(prefix, completion);
            }
            return completion;
        }
        return super.getPrefixCompletionText(document, completionOffset);
    }

    /**
     * Appends everything up to the method name including the opening parenthesis.
     * <p>
     * 
     * @param buffer the string buffer
     */
    protected void appendMethodNameReplacement(StringBuffer buffer) {
        if (fProposal.getKind() != CompletionProposal.CONSTRUCTOR_INVOCATION) {
            buffer.append(fProposal.getName());
        }

        FormatterPrefs prefs = getFormatterPrefs();
        if (prefs.beforeOpeningParen) {
            buffer.append(SPACE);
        }
        buffer.append(LPAREN);
    }

    @Override
    protected IContextInformation computeContextInformation() {
        // no context information for METHOD_NAME_REF proposals (e.g. for static imports)
        if ((fProposal.getKind() == CompletionProposal.METHOD_REF
                || fProposal.getKind() == CompletionProposal.CONSTRUCTOR_INVOCATION) && hasParameters()
                && (getReplacementString().endsWith(RPAREN) || getReplacementString().length() == 0)) {
            ProposalContextInformation contextInformation = new ProposalContextInformation(fProposal);
            if (fContextInformationPosition != 0 && fProposal.getCompletion().length == 0) {
                contextInformation.setContextInformationPosition(fContextInformationPosition);
            }
            return contextInformation;
        }
        return super.computeContextInformation();
    }

    @Override
    protected ProposalInfo computeProposalInfo() {
        DartProject project = fInvocationContext.getProject();
        if (project != null) {
            return new MethodProposalInfo(project, fProposal);
        }
        return super.computeProposalInfo();
    }

    @Override
    protected String computeReplacementString() {
        if (!hasArgumentList()) {
            return super.computeReplacementString();
        }

        // we're inserting a method plus the argument list - respect formatter preferences
        StringBuffer buffer = new StringBuffer();
        appendMethodNameReplacement(buffer);

        FormatterPrefs prefs = getFormatterPrefs();

        if (hasParameters()) {
            setCursorPosition(buffer.length());

            if (prefs.afterOpeningParen) {
                buffer.append(SPACE);
            }

        } else {
            if (prefs.inEmptyList) {
                buffer.append(SPACE);
            }
        }

        buffer.append(RPAREN);

        return buffer.toString();

    }

    @Override
    protected String computeSortString() {
        /*
         * Lexicographical sort order: 1) by relevance (done by the proposal sorter) 2) by method name
         * 3) by parameter count 4) by parameter type names
         */
        char[] name = fProposal.getName();
        char[] parameterList = Signature.toCharArray(fProposal.getSignature(), null, null, false, false);
        int parameterCount = fProposal.getParameterNames().length % 10; // we don't care about insane methods with >9 parameters
        StringBuffer buf = new StringBuffer(name.length + 2 + parameterList.length);

        buf.append(name);
        buf.append('\0'); // separator
        buf.append(parameterCount);
        buf.append(parameterList);
        return buf.toString();
    }

    @Override
    protected char[] computeTriggerCharacters() {
        if (fProposal.getKind() == CompletionProposal.METHOD_NAME_REFERENCE) {
            return METHOD_NAME_TRIGGERS;
        }
        if (hasParameters()) {
            return METHOD_WITH_ARGUMENTS_TRIGGERS;
        }
        return METHOD_TRIGGERS;
    }

    /**
     * Returns the method formatter preferences.
     * 
     * @return the formatter settings
     */
    @Override
    protected final FormatterPrefs getFormatterPrefs() {
        if (fFormatterPrefs == null) {
            fFormatterPrefs = new FormatterPrefs(fInvocationContext.getProject());
        }
        return fFormatterPrefs;
    }

    @Override
    protected String getPrefix(IDocument document, int offset) {
        if (fProposal.getKind() != CompletionProposal.CONSTRUCTOR_INVOCATION) {
            return super.getPrefix(document, offset);
        }

        int replacementOffset = fProposal.getRequiredProposals()[0].getReplaceStart();

        try {
            int length = offset - replacementOffset;
            if (length > 0) {
                return document.get(replacementOffset, length);
            }
        } catch (BadLocationException x) {
        }
        return ""; //$NON-NLS-1$

    }

    /**
     * Returns <code>true</code> if the argument list should be inserted by the proposal,
     * <code>false</code> if not.
     * 
     * @return <code>true</code> when the proposal is not in javadoc nor within an import and
     *         comprises the parameter list
     */
    protected boolean hasArgumentList() {
        if (CompletionProposal.METHOD_NAME_REFERENCE == fProposal.getKind()) {
            return false;
        }
        IPreferenceStore preferenceStore = DartToolsPlugin.getDefault().getPreferenceStore();
        boolean noOverwrite = preferenceStore.getBoolean(PreferenceConstants.CODEASSIST_INSERT_COMPLETION)
                ^ isToggleEating();
        char[] completion = fProposal.getCompletion();
        return !isInDartDoc() && completion.length > 0 && (noOverwrite || completion[completion.length - 1] == ')');
    }

    /**
     * Returns <code>true</code> if the method being inserted has at least one parameter. Note that
     * this does not say anything about whether the argument list should be inserted. This depends on
     * the position in the document and the kind of proposal; see {@link #hasArgumentList() }.
     * 
     * @return <code>true</code> if the method has any parameters, <code>false</code> if it has no
     *         parameters
     */
    protected final boolean hasParameters() {
        if (!fHasParametersComputed) {
            fHasParametersComputed = true;
            fHasParameters = computeHasParameters();
        }
        return fHasParameters;
    }

    @Override
    protected boolean isOffsetValid(int offset) {
        if (fProposal.getKind() != CompletionProposal.CONSTRUCTOR_INVOCATION) {
            return super.isOffsetValid(offset);
        }

        return fProposal.getRequiredProposals()[0].getReplaceStart() <= offset;
    }

    @Override
    protected boolean isValidPrefix(String prefix) {
        if (super.isValidPrefix(prefix)) {
            return true;
        }

        String word = TextProcessor.deprocess(getDisplayString());
        if (fProposal.getKind() == CompletionProposal.CONSTRUCTOR_INVOCATION) {
            int start = word.indexOf(DartElementLabels.CONCAT_STRING) + DartElementLabels.CONCAT_STRING.length();
            word = word.substring(start);
            return isPrefix(prefix, word) || isPrefix(prefix, new String(fProposal.getName()));
        }

        if (isInDartDoc()) {
            int idx = word.indexOf("{@link "); //$NON-NLS-1$
            if (idx == 0) {
                word = word.substring(7);
            } else {
                idx = word.indexOf("{@value "); //$NON-NLS-1$
                if (idx == 0) {
                    word = word.substring(8);
                }
            }
        }
        return isPrefix(prefix, word);
    }

    protected boolean needsLinkedMode() {
        return hasArgumentList() && hasParameters();
    }

    private boolean computeHasParameters() throws IllegalArgumentException {
        return getProposal().getParameterNames().length > 0;
    }
}