blob: 1605c7b58aedaaa1977f75b5d1a2d4804f7e70c2 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009 University of Illinois at Urbana-Champaign 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:
* UIUC - Initial API and implementation
*******************************************************************************/
package org.eclipse.photran.internal.ui.editor_vpg.contentassist;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.TreeSet;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.contentassist.ContentAssistant;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
import org.eclipse.jface.text.contentassist.IContentAssistant;
import org.eclipse.jface.text.contentassist.IContextInformation;
import org.eclipse.jface.text.contentassist.IContextInformationValidator;
import org.eclipse.photran.internal.core.analysis.binding.Definition;
import org.eclipse.photran.internal.core.properties.SearchPathProperties;
import org.eclipse.photran.internal.ui.editor.FortranEditor;
import org.eclipse.photran.internal.ui.editor.FortranTemplateCompletionProcessor;
import org.eclipse.photran.internal.ui.editor_vpg.FortranEditorTasks;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.RGB;
/**
* Fortran content assist processor which uses the VPG to determine which identifiers are in scope.
*
* @author Jeff Overbey
*/
public class FortranCompletionProcessor implements IContentAssistProcessor
{
/** Scope map: scopes.get(n) is the qualified name of the scope at line (n+1) */
ArrayList<String> scopes = new ArrayList<String>();
/** Maps qualified scope names to lists of definitions declared in that scope */
HashMap<String, TreeSet<Definition>> defs = new HashMap<String, TreeSet<Definition>>();
private String errorMessage = null;
//private final Color LIGHT_YELLOW = new Color(null, new RGB(255, 255, 191));
private final Color LIGHT_YELLOW = new Color(null, new RGB(255, 255, 223));
//private final Color WHITE = new Color(null, new RGB(255, 255, 255));
public IContentAssistant setup(FortranEditor editor)
{
String contentAssistEnabledProperty = new SearchPathProperties().getProperty(
editor.getIFile(),
SearchPathProperties.ENABLE_CONTENT_ASSIST_PROPERTY_NAME);
if (contentAssistEnabledProperty != null && contentAssistEnabledProperty.equals("true")) //$NON-NLS-1$
{
FortranEditorTasks.instance(editor).addASTTask(new FortranCompletionProcessorASTTask(this));
FortranEditorTasks.instance(editor).addVPGTask(new FortranCompletionProcessorVPGTask(this));
ContentAssistant assistant = new ContentAssistant();
for (String partitionType : FortranEditor.PARTITION_TYPES)
assistant.setContentAssistProcessor(this, partitionType);
assistant.enableAutoActivation(false); //assistant.setAutoActivationDelay(500);
assistant.setProposalPopupOrientation(IContentAssistant.CONTEXT_INFO_BELOW);
assistant.setContextInformationPopupBackground(LIGHT_YELLOW);
assistant.setProposalSelectorBackground(LIGHT_YELLOW);
return assistant;
}
else return null;
}
public synchronized ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset)
{
FortranCompletionProposalComputer computer = null;
List<ICompletionProposal> proposals = new ArrayList<ICompletionProposal>(256);
if (defs != null)
{
// return new ICompletionProposal[]
// {
// new CompletionProposal("Hello", offset, 0, 5),
// new CompletionProposal("Goodbye", offset, 0, 7)
// };
try
{
errorMessage = null;
IDocument document = viewer.getDocument();
int line = determineLineNumberForOffset(offset, document);
String scopeName = determineScopeNameForLine(line);
if (scopeName != null)
computer = new FortranCompletionProposalComputer(defs, scopeName, document, offset);
// Include proposals in this order:
// 1. Local variables, functions, etc.
if (computer != null) proposals.addAll(computer.proposalsFromDefs());
// 2. Code templates
for (ICompletionProposal proposal : new FortranTemplateCompletionProcessor().computeCompletionProposals(viewer, offset))
proposals.add(proposal);
// 3. Intrinsic procedures
if (computer != null) proposals.addAll(computer.proposalsFromIntrinsics());
}
catch (Exception e)
{
errorMessage = e.getClass().getName() + " - " + e.getMessage(); //$NON-NLS-1$
}
}
return proposals.toArray(new ICompletionProposal[proposals.size()]);
}
private int determineLineNumberForOffset(int offset, IDocument document) throws BadLocationException
{
int line = document.getLineOfOffset(offset);
/*
* The mapping between scopes and lines is reconfigured only when
* the editor is reconciled and a new AST is available. Therefore,
* if the user adds a line or two at the bottom of the file and
* invokes content assist before the editor can be reconciled, the
* line number may be greater than what the last line of the file
* was the last time we parsed it. In this case, reset the line
* to be the last line of the file.
*/
if (!scopes.isEmpty() && line >= scopes.size())
line = scopes.size()-1;
return line;
}
private final String determineScopeNameForLine(int line)
{
String scopeName = ""; //$NON-NLS-1$
if (line < scopes.size())
scopeName = scopes.get(line);
if (scopeName == null)
scopeName = ""; //$NON-NLS-1$
/*
* Again, the mapping between scopes and lines is reconfigured only
* when the editor is reconciled and a new AST is available. If
* the user invokes content assist and the scope is reported to be
* the outermost scope (""), it's probably because the user has
* added lines beyond the end-statement of the previous program
* unit and the editor hasn't been reconciled yet. (The outermost
* scope usually contains just a single module or program, so
* it is rare that a user would type anything below the
* first program unit, particularly in the outermost scope).
* Therefore, populate the list of completion proposals based on
* the *preceding* scope.
*/
while (scopeName.equals("") && line > 0) //$NON-NLS-1$
{
line--;
if (line < scopes.size())
scopeName = scopes.get(line);
}
return scopeName;
}
public IContextInformation[] computeContextInformation(ITextViewer viewer,
int offset)
{
return null;
}
public char[] getCompletionProposalAutoActivationCharacters()
{
return null;
}
public char[] getContextInformationAutoActivationCharacters()
{
return null;
}
public IContextInformationValidator getContextInformationValidator()
{
return null;
}
public String getErrorMessage()
{
return errorMessage;
}
}