Commit 1109a525 authored by Philip Makedonski's avatar Philip Makedonski
Browse files

+ further refinements to completions, retain last used kind, ignore kinds when...

+ further refinements to completions, retain last used kind, ignore kinds when not applicable, #230, #255
parent ade2abc0
Loading
Loading
Loading
Loading
Loading
+76 −9
Changes for plugins/org.etsi.mts.tdl.tx.ui/src/org/etsi/mts/tdl/ui/contentassist/CyclingContentAssistProcessor.java: 76 added lines, 9 removed lines.
Original line number Diff line number Diff line
package org.etsi.mts.tdl.ui.contentassist;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;

import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.contentassist.ContentAssistEvent;
@@ -17,18 +21,32 @@ public class CyclingContentAssistProcessor extends XtextContentAssistProcessor
        implements ICompletionListener {

    private enum Kind { ALL, TYPES, VALUES, NESTED }
    private int iteration = 0;
    // static = shared across all editors, lost on Eclipse restart
    private static int lastKindIndex = 0;

    private int iteration = 0;      // drives cycling within a session
    private int shownIndex = 0;     // index of the kind currently displayed
    private int calls = 0;                  // compute calls in this session
    private boolean fellBack = false;       // first call had to skip the remembered kind
    private ContentAssistant assistant;

    @Override
    public void assistSessionStarted(ContentAssistEvent e) { 
    	iteration = 0; 
//    	iteration = 0; 
        iteration = lastKindIndex;  // start from the remembered kind
        calls = 0;
        fellBack = false;
        assistant = (ContentAssistant) e.assistant;
        updateStatusMessage();
 	}
    @Override
    public void assistSessionEnded(ContentAssistEvent e) { 
    	iteration = 0;
//    	iteration = 0;
        //lastKindIndex = shownIndex; // remember what was showing when the popup closed
    	// Don't overwrite the preference with a fallback the user never chose.
        if (!(fellBack && calls == 1)) {
            lastKindIndex = shownIndex;
        }
        assistant = null;
	}
    @Override
@@ -37,12 +55,60 @@ public class CyclingContentAssistProcessor extends XtextContentAssistProcessor
    @Override
    public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) {
    	ICompletionProposal[] all = super.computeCompletionProposals(viewer, offset);
    	Kind kind = Kind.values()[iteration % Kind.values().length];
        iteration++;
        updateStatusMessage();   // now shows the kind of the *next* press
        return Arrays.stream(all)
                .filter(p -> matches(p, kind))
                .toArray(ICompletionProposal[]::new);
        Map<Kind, List<ICompletionProposal>> byKind = classify(all);
        int n = Kind.values().length;
        calls++;

        int start = iteration % n;
        int chosen = nextNonEmpty(byKind, start);
        if (chosen < 0) {
            chosen = start;                 // nothing matches at all: show the (empty) requested kind
        } else if (calls == 1 && chosen != start) {
            fellBack = true;
        }

        shownIndex = chosen;
        iteration = chosen + 1;
        updateStatusMessage(byKind);
	    return byKind.get(Kind.values()[chosen]).toArray(new ICompletionProposal[0]);
    }

    /** First index >= from (wrapping) whose kind has proposals, or -1. */
    private int nextNonEmpty(Map<Kind, List<ICompletionProposal>> byKind, int from) {
        Kind[] kinds = Kind.values();
        for (int i = 0; i < kinds.length; i++) {
            int idx = (from + i) % kinds.length;
            if (!byKind.get(kinds[idx]).isEmpty()) {
                return idx;
            }
        }
        return -1;
    }
    
    private void updateStatusMessage(Map<Kind, List<ICompletionProposal>> byKind) {
        if (assistant == null) return;
        int n = Kind.values().length;
        int next = nextNonEmpty(byKind, iteration % n);
        if (next >= 0 && next != shownIndex) {
            assistant.setStatusMessage("Press Ctrl+Space for " + Kind.values()[next] + " proposals");
        } else {
            assistant.setStatusMessage("No other proposal kinds available here");
        }
    }
    
    private Map<Kind, List<ICompletionProposal>> classify(ICompletionProposal[] all) {
        Map<Kind, List<ICompletionProposal>> byKind = new EnumMap<>(Kind.class);
        for (Kind k : Kind.values()) {
            byKind.put(k, new ArrayList<>());
        }
        for (ICompletionProposal p : all) {
            byKind.get(Kind.ALL).add(p);        // ALL always contains everything
            Kind k = kindOf(p);                 // your classification from step 1
            if (k != null && k != Kind.ALL) {
                byKind.get(k).add(p);
            }
        }
        return byKind;
    }
    
    private boolean matches(ICompletionProposal p, Kind kind) {
@@ -64,6 +130,7 @@ public class CyclingContentAssistProcessor extends XtextContentAssistProcessor
		}
		return Kind.ALL;
	}
	
	private void updateStatusMessage() {
        if (assistant == null) return;
        Kind next = Kind.values()[iteration % Kind.values().length];
+2 −2
Changes for plugins/org.etsi.mts.tdl.tx.ui/src/org/etsi/mts/tdl/ui/contentassist/TDLtxProposalProvider.java: 2 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -822,7 +822,7 @@ public class TDLtxProposalProvider extends AbstractTDLtxProposalProvider {
	}
	
	public void completeVariableUse_ComponentInstance(EObject model, Assignment assignment, ContentAssistContext context, ICompletionProposalAcceptor acceptor) {
		if (model instanceof ParameterBinding || model instanceof MemberReference) {
		if (model instanceof ParameterBinding || model instanceof MemberReference || model instanceof DataElementUse) {
			return;
		}
		//super lookupCrossReference
@@ -862,7 +862,7 @@ public class TDLtxProposalProvider extends AbstractTDLtxProposalProvider {


	public void completeDataElementUse_DataElement(EObject model, Assignment assignment, ContentAssistContext context, ICompletionProposalAcceptor acceptor) {
		if (model instanceof ParameterBinding || model instanceof MemberAssignment || model instanceof MemberReference || model instanceof DataReference || model instanceof Message) {
		if (model instanceof ParameterBinding || model instanceof MemberAssignment || model instanceof MemberReference || model instanceof DataReference || model instanceof Message || model instanceof DataElementUse) {
//			complete_ParameterBinding(model, ruleCall, context, acceptor);
			return;
		}