aboutsummaryrefslogtreecommitdiffstats
path: root/language-ide/src/main/java/org/eclipse/viatra/solver/language/ide/syntaxcoloring/ProblemSemanticHighlightingCalculator.java
blob: f9a1fb7b97ef8de66170928a05bc95e746bcf1f6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package org.eclipse.viatra.solver.language.ide.syntaxcoloring;

import java.util.List;

import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.viatra.solver.language.ProblemUtil;
import org.eclipse.viatra.solver.language.model.problem.ClassDeclaration;
import org.eclipse.viatra.solver.language.model.problem.EnumDeclaration;
import org.eclipse.viatra.solver.language.model.problem.NamedElement;
import org.eclipse.viatra.solver.language.model.problem.Node;
import org.eclipse.viatra.solver.language.model.problem.Parameter;
import org.eclipse.viatra.solver.language.model.problem.PredicateDefinition;
import org.eclipse.viatra.solver.language.model.problem.ProblemPackage;
import org.eclipse.viatra.solver.language.model.problem.ReferenceDeclaration;
import org.eclipse.viatra.solver.language.model.problem.Variable;
import org.eclipse.xtext.ide.editor.syntaxcoloring.DefaultSemanticHighlightingCalculator;
import org.eclipse.xtext.ide.editor.syntaxcoloring.IHighlightedPositionAcceptor;
import org.eclipse.xtext.nodemodel.INode;
import org.eclipse.xtext.nodemodel.util.NodeModelUtils;
import org.eclipse.xtext.service.OperationCanceledManager;
import org.eclipse.xtext.util.CancelIndicator;

import com.google.common.collect.ImmutableList;
import com.google.inject.Inject;

public class ProblemSemanticHighlightingCalculator extends DefaultSemanticHighlightingCalculator {
	private static final String BUILTIN_CLASS = "cm-keyword";
	private static final String CLASS_CLASS = "problem-class";
	private static final String ABSTRACT_CLASS = "problem-abstract";
	private static final String ENUM_CLASS = "problem-enum";
	private static final String REFERENCE_CLASS = "problem-reference";
	private static final String CONTAINMENT_CLASS = "problem-containment";
	private static final String PREDICATE_CLASS = "problem-predicate";
	private static final String ERROR_CLASS = "problem-error";
	private static final String NODE_CLASS = "problem-node";
	private static final String UNIQUE_NODE_CLASS = "problem-unique-node";
	private static final String NEW_NODE_CLASS = "problem-new-node";
	private static final String PARAMETER_CLASS = "problem-parameter";
	private static final String VARIABLE_CLASS = "problem-variable";
	private static final String SINGLETON_VARIABLE_CLASS = "problem-singleton-variable";

	@Inject
	private OperationCanceledManager operationCanceledManager;

	@Override
	protected boolean highlightElement(EObject object, IHighlightedPositionAcceptor acceptor,
			CancelIndicator cancelIndicator) {
		highlightName(object, acceptor);
		highlightCrossReferences(object, acceptor, cancelIndicator);
		return false;
	}

	protected void highlightName(EObject object, IHighlightedPositionAcceptor acceptor) {
		if (!(object instanceof NamedElement)) {
			return;
		}
		String[] highlightClass = getHighlightClass(object);
		if (highlightClass.length > 0) {
			highlightFeature(acceptor, object, ProblemPackage.Literals.NAMED_ELEMENT__NAME, highlightClass);
		}
	}

	protected void highlightCrossReferences(EObject object, IHighlightedPositionAcceptor acceptor,
			CancelIndicator cancelIndicator) {
		for (EReference reference : object.eClass().getEAllReferences()) {
			if (reference.isContainment()) {
				continue;
			}
			operationCanceledManager.checkCanceled(cancelIndicator);
			if (reference.isMany()) {
				highlightManyValues(object, reference, acceptor);
			} else {
				highlightSingleValue(object, reference, acceptor);
			}
		}
	}

	protected void highlightSingleValue(EObject object, EReference reference, IHighlightedPositionAcceptor acceptor) {
		EObject valueObj = (EObject) object.eGet(reference);
		String[] highlightClass = getHighlightClass(valueObj);
		if (highlightClass.length > 0) {
			highlightFeature(acceptor, object, reference, highlightClass);
		}
	}

	protected void highlightManyValues(EObject object, EReference reference, IHighlightedPositionAcceptor acceptor) {
		@SuppressWarnings("unchecked")
		EList<? extends EObject> values = (EList<? extends EObject>) object.eGet(reference);
		List<INode> nodes = NodeModelUtils.findNodesForFeature(object, reference);
		int size = Math.min(values.size(), nodes.size());
		for (var i = 0; i < size; i++) {
			EObject valueInList = values.get(i);
			INode node = nodes.get(i);
			String[] highlightClass = getHighlightClass(valueInList);
			if (highlightClass.length > 0) {
				highlightNode(acceptor, node, highlightClass);
			}
		}
	}

	protected String[] getHighlightClass(EObject eObject) {
		if (ProblemUtil.isBuiltIn(eObject)) {
			return new String[] { BUILTIN_CLASS };
		}
		ImmutableList.Builder<String> classesBuilder = ImmutableList.builder();
		if (eObject instanceof ClassDeclaration) {
			classesBuilder.add(CLASS_CLASS);
			var classDeclaration = (ClassDeclaration) eObject;
			if (classDeclaration.isAbstract()) {
				classesBuilder.add(ABSTRACT_CLASS);
			}
		}
		if (eObject instanceof EnumDeclaration) {
			classesBuilder.add(ENUM_CLASS);
		}
		if (eObject instanceof ReferenceDeclaration) {
			classesBuilder.add(REFERENCE_CLASS);
			var referenceDeclaration = (ReferenceDeclaration) eObject;
			if (referenceDeclaration.isContainment()) {
				classesBuilder.add(CONTAINMENT_CLASS);
			}
		}
		if (eObject instanceof PredicateDefinition) {
			classesBuilder.add(PREDICATE_CLASS);
			var predicateDefinition = (PredicateDefinition) eObject;
			if (predicateDefinition.isError()) {
				classesBuilder.add(ERROR_CLASS);
			}
		}
		if (eObject instanceof Node) {
			classesBuilder.add(NODE_CLASS);
			var node = (Node) eObject;
			if (ProblemUtil.isUniqueNode(node)) {
				classesBuilder.add(UNIQUE_NODE_CLASS);
			}
			if (ProblemUtil.isNewNode(node)) {
				classesBuilder.add(NEW_NODE_CLASS);
			}
		}
		if (eObject instanceof Parameter) {
			classesBuilder.add(PARAMETER_CLASS);
		}
		if (eObject instanceof Variable) {
			classesBuilder.add(VARIABLE_CLASS);
			var variable = (Variable) eObject;
			if (ProblemUtil.isSingletonVariable(variable)) {
				classesBuilder.add(SINGLETON_VARIABLE_CLASS);
			}
		}
		List<String> classes = classesBuilder.build();
		return classes.toArray(new String[0]);
	}
}