package org.jmlspecs.openjml.eclipse; import java.util.EnumSet; import java.util.LinkedList; import java.util.List; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jdt.ui.text.java.ContentAssistInvocationContext; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.contentassist.CompletionProposal; import org.eclipse.jface.text.contentassist.ICompletionProposal; import org.eclipse.jface.text.contentassist.IContextInformation; import org.jmlspecs.openjml.JmlTokenKind; public class ProposalComputer implements org.eclipse.jdt.ui.text.java.IJavaCompletionProposalComputer { @Override public void sessionStarted() { } public final static EnumSet<JmlTokenKind> keywords = EnumSet.range(JmlTokenKind.ASSUME,JmlTokenKind.NOWARN); @Override public List<ICompletionProposal> computeCompletionProposals( ContentAssistInvocationContext context, IProgressMonitor monitor) { // TODO Auto-generated method stub List<ICompletionProposal> proposals = new LinkedList<ICompletionProposal>(); int pos = context.getInvocationOffset(); IDocument doc = context.getDocument(); // Keyword proposals int backslashPos = -1; int firstSpace = -1; int p = pos - 1; kw: try { while (p >= 0) { char c = doc.getChar(p); if (c == ' ' || c == '\t') { if (firstSpace < 0) firstSpace = p; } else if (c == ';' || c == '@') { if (firstSpace < 0) firstSpace = p; break; } else if (c == '\\') { backslashPos = p; break; } else { if (firstSpace >= 0) break kw; // Not in a position for keywords } --p; } // FIXME - want to allow code completion for modifiers that are not necessarily first // FIXME - want to add code completion for variables as well; what about expressions? if (backslashPos >= 0) { String prefix = doc.get(backslashPos,pos-backslashPos); for (String s: JmlTokenKind.backslashTokens.keySet()){ if (s.startsWith(prefix)) { proposals.add(new CompletionProposal(s,backslashPos,pos-backslashPos,s.length())); } } } else { String prefix = doc.get(firstSpace+1,pos-firstSpace-1); for (JmlTokenKind t: keywords) { String s = t.internedName(); if (s != null && s.startsWith(prefix)) { proposals.add(new CompletionProposal(s,firstSpace+1,pos-firstSpace-1,s.length())); } } } } catch (BadLocationException e) { // go on to propose nothing } return proposals; } @Override public List<IContextInformation> computeContextInformation( ContentAssistInvocationContext context, IProgressMonitor monitor) { // TODO: Not sure when this is used or what the appropriate result should be return null; } @Override public String getErrorMessage() { // TODO: Not sure when this is used return "No JML keywords match this prefix"; } @Override public void sessionEnded() { } }