com.reprezen.swagedit.assist.SwaggerContentAssistProcessor.java Source code

Java tutorial

Introduction

Here is the source code for com.reprezen.swagedit.assist.SwaggerContentAssistProcessor.java

Source

/*******************************************************************************
 * Copyright (c) 2016 ModelSolv, Inc. and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    ModelSolv, Inc. - initial API and implementation and/or initial documentation
 *******************************************************************************/
package com.reprezen.swagedit.assist;

import static org.eclipse.ui.IWorkbenchCommandConstants.EDIT_CONTENT_ASSIST;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.contentassist.ContentAssistEvent;
import org.eclipse.jface.text.contentassist.ContentAssistant;
import org.eclipse.jface.text.contentassist.ICompletionListener;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
import org.eclipse.jface.text.contentassist.IContextInformation;
import org.eclipse.jface.text.contentassist.IContextInformationValidator;
import org.eclipse.jface.text.templates.ContextTypeRegistry;
import org.eclipse.jface.text.templates.DocumentTemplateContext;
import org.eclipse.jface.text.templates.Template;
import org.eclipse.jface.text.templates.TemplateCompletionProcessor;
import org.eclipse.jface.text.templates.TemplateContext;
import org.eclipse.jface.text.templates.TemplateContextType;
import org.eclipse.jface.text.templates.persistence.TemplateStore;
import org.eclipse.jface.viewers.StyledString;
import org.eclipse.jface.viewers.StyledString.Styler;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.TextStyle;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.keys.IBindingService;

import com.fasterxml.jackson.core.JsonPointer;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.reprezen.swagedit.Activator;
import com.reprezen.swagedit.Activator.Icons;
import com.reprezen.swagedit.Messages;
import com.reprezen.swagedit.assist.JsonReferenceProposalProvider.ContextType;
import com.reprezen.swagedit.assist.ext.MediaTypeContentAssistExt;
import com.reprezen.swagedit.editor.SwaggerDocument;
import com.reprezen.swagedit.json.references.JsonReference;
import com.reprezen.swagedit.model.Model;
import com.reprezen.swagedit.templates.SwaggerContextType;
import com.reprezen.swagedit.templates.SwaggerTemplateContext;
import com.reprezen.swagedit.utils.SwaggerFileFinder.Scope;

/**
 * This class provides basic content assist based on keywords used by the swagger schema.
 */
public class SwaggerContentAssistProcessor extends TemplateCompletionProcessor
        implements IContentAssistProcessor, ICompletionListener {

    private final SwaggerProposalProvider proposalProvider = new SwaggerProposalProvider(
            new MediaTypeContentAssistExt());

    private final JsonReferenceProposalProvider referenceProposalProvider = new JsonReferenceProposalProvider();
    private final ContentAssistant contentAssistant;

    /**
     * The pointer that helps us locate the current position of the cursor inside the document.
     * 
     */
    private JsonPointer currentPath = null;

    /**
     * Current position scope use to retrieve JSON Reference proposals.
     */
    private Scope currentScope = Scope.LOCAL;

    /**
     * True if the proposal is activated on a JSON reference.
     */
    private boolean isRefCompletion = false;

    private String[] textMessages;

    public SwaggerContentAssistProcessor() {
        this(null);
    }

    public SwaggerContentAssistProcessor(ContentAssistant ca) {
        this.contentAssistant = ca;
        this.textMessages = initTextMessages();
    }

    @Override
    public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int documentOffset) {
        if (!(viewer.getDocument() instanceof SwaggerDocument)) {
            return super.computeCompletionProposals(viewer, documentOffset);
        }

        if (isRefCompletion) {
            currentScope = currentScope.next();
        }

        final SwaggerDocument document = (SwaggerDocument) viewer.getDocument();
        final ITextSelection selection = (ITextSelection) viewer.getSelectionProvider().getSelection();
        int line = 0, lineOffset = 0, column = 0;
        try {
            line = document.getLineOfOffset(documentOffset);
            lineOffset = document.getLineOffset(line);
            column = selection.getOffset() - lineOffset;
        } catch (BadLocationException e) {
        }

        final String prefix = extractPrefix(viewer, documentOffset);
        // we have to remove the length of
        // the prefix to obtain the correct
        // column to resolve the path
        if (!prefix.isEmpty()) {
            column -= prefix.length();
        }

        Model model = document.getModel(documentOffset - prefix.length());
        currentPath = model.getPath(line, column);

        isRefCompletion = currentPath != null && currentPath.toString().endsWith(JsonReference.PROPERTY);

        Collection<Proposal> p;
        if (isRefCompletion) {
            updateStatus();
            p = referenceProposalProvider.getProposals(currentPath, document.asJson(), currentScope);
        } else {
            clearStatus();
            p = proposalProvider.getProposals(currentPath, model, prefix);
        }

        final Collection<ICompletionProposal> proposals = getCompletionProposals(p, prefix, documentOffset);
        // compute template proposals
        if (!isRefCompletion) {
            final ICompletionProposal[] templateProposals = super.computeCompletionProposals(viewer,
                    documentOffset);
            if (templateProposals != null && templateProposals.length > 0) {
                proposals.addAll(Lists.newArrayList(templateProposals));
            }
        }

        return proposals.toArray(new ICompletionProposal[proposals.size()]);
    }

    protected void updateStatus() {
        if (contentAssistant != null) {
            if (textMessages == null) {
                textMessages = initTextMessages();
            }
            contentAssistant.setStatusLineVisible(true);
            contentAssistant.setStatusMessage(textMessages[currentScope.getValue()]);
        }
    }

    protected void clearStatus() {
        if (contentAssistant != null) {
            contentAssistant.setStatusLineVisible(false);
        }
    }

    protected String[] initTextMessages() {
        IBindingService bindingService = (IBindingService) PlatformUI.getWorkbench()
                .getAdapter(IBindingService.class);
        String bindingKey = bindingService.getBestActiveBindingFormattedFor(EDIT_CONTENT_ASSIST);

        ContextType contextType = ContextType.get(currentPath != null ? currentPath.toString() : "");
        String context = contextType != null ? contextType.label() : "";

        return new String[] { //
                String.format(Messages.content_assist_proposal_project, bindingKey, context),
                String.format(Messages.content_assist_proposal_workspace, bindingKey, context),
                String.format(Messages.content_assist_proposal_local, bindingKey, context) };
    }

    protected Collection<ICompletionProposal> getCompletionProposals(Collection<Proposal> proposals, String prefix,
            int offset) {
        final List<ICompletionProposal> result = new ArrayList<>();

        prefix = Strings.emptyToNull(prefix);

        for (Proposal proposal : proposals) {
            StyledCompletionProposal styledProposal = proposal.asStyledCompletionProposal(prefix, offset);
            if (styledProposal != null) {
                result.add(styledProposal);
            }
        }

        return result;
    }

    @Override
    protected String extractPrefix(ITextViewer viewer, int offset) {
        int i = offset;
        IDocument document = viewer.getDocument();
        if (i > document.getLength())
            return ""; //$NON-NLS-1$

        try {
            while (i > 0) {
                char ch = document.getChar(i - 1);
                if (Character.isWhitespace(ch))
                    break;
                i--;
            }

            return document.get(i, offset - i);
        } catch (BadLocationException e) {
            return ""; //$NON-NLS-1$
        }
    }

    @Override
    public IContextInformation[] computeContextInformation(ITextViewer viewer, int offset) {
        return null;
    }

    @Override
    public char[] getCompletionProposalAutoActivationCharacters() {
        return new char[] {};
    }

    @Override
    public char[] getContextInformationAutoActivationCharacters() {
        return null;
    }

    @Override
    public String getErrorMessage() {
        return null;
    }

    @Override
    public IContextInformationValidator getContextInformationValidator() {
        return null;
    }

    @Override
    protected ICompletionProposal createProposal(Template template, TemplateContext context, IRegion region,
            int relevance) {
        if (context instanceof DocumentTemplateContext) {
            context = new SwaggerTemplateContext((DocumentTemplateContext) context);
        }
        return new StyledTemplateProposal(template, context, region, getImage(template), getTemplateLabel(template),
                relevance);
    }

    @Override
    protected Template[] getTemplates(String contextTypeId) {
        return geTemplateStore().getTemplates();
    }

    @Override
    protected TemplateContextType getContextType(ITextViewer viewer, IRegion region) {
        String contextType = SwaggerContextType.getContextType(currentPath.toString());
        ContextTypeRegistry registry = getContextTypeRegistry();
        if (registry != null) {
            return registry.getContextType(contextType);
        } else {
            return null;
        }
    }

    @Override
    protected Image getImage(Template template) {
        return Activator.getDefault().getImage(Icons.template_item);
    }

    protected TemplateStore geTemplateStore() {
        return Activator.getDefault().getTemplateStore();
    }

    protected ContextTypeRegistry getContextTypeRegistry() {
        return Activator.getDefault().getContextTypeRegistry();
    }

    protected StyledString getTemplateLabel(Template template) {
        Styler nameStyle = new StyledString.Styler() {
            @Override
            public void applyStyles(TextStyle textStyle) {
                textStyle.foreground = new Color(Display.getCurrent(), new RGB(80, 80, 255));
            }
        };
        Styler descriptionStyle = new StyledString.Styler() {
            @Override
            public void applyStyles(TextStyle textStyle) {
                textStyle.foreground = new Color(Display.getCurrent(), new RGB(120, 120, 120));
            }
        };

        return new StyledString(template.getName(), nameStyle).append(": ", descriptionStyle)
                .append(template.getDescription(), descriptionStyle);
    }

    @Override
    public void assistSessionStarted(ContentAssistEvent event) {
        currentScope = Scope.LOCAL;
        isRefCompletion = false;
        textMessages = null;
    }

    @Override
    public void assistSessionEnded(ContentAssistEvent event) {
        currentScope = Scope.LOCAL;
        isRefCompletion = false;
        textMessages = null;
    }

    @Override
    public void selectionChanged(ICompletionProposal proposal, boolean smartToggle) {
    }

}