Merge "Bug 536769 - [room.ui] Use new DC tools for content assist" into newfsmgen_finalize
diff --git a/plugins/org.eclipse.etrice.core.room.ui/META-INF/MANIFEST.MF b/plugins/org.eclipse.etrice.core.room.ui/META-INF/MANIFEST.MF
index 1db465e..adb6cff 100644
--- a/plugins/org.eclipse.etrice.core.room.ui/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.etrice.core.room.ui/META-INF/MANIFEST.MF
@@ -23,7 +23,9 @@
  org.eclipse.core.filesystem;bundle-version="1.3.0",
  org.eclipse.help,
  com.google.inject,
- org.eclipse.etrice.expressions.ui
+ org.eclipse.etrice.expressions.ui,
+ org.eclipse.etrice.ui.behavior.fsm;bundle-version="1.1.1",
+ org.eclipse.etrice.dctools;bundle-version="1.1.1"
 Import-Package: org.apache.log4j
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Export-Package: org.eclipse.etrice.core.ui,
diff --git a/plugins/org.eclipse.etrice.core.room.ui/src/org/eclipse/etrice/core/ui/contentassist/RoomProposalProvider.java b/plugins/org.eclipse.etrice.core.room.ui/src/org/eclipse/etrice/core/ui/contentassist/RoomProposalProvider.java
index 2bb4233..30b9f23 100644
--- a/plugins/org.eclipse.etrice.core.room.ui/src/org/eclipse/etrice/core/ui/contentassist/RoomProposalProvider.java
+++ b/plugins/org.eclipse.etrice.core.room.ui/src/org/eclipse/etrice/core/ui/contentassist/RoomProposalProvider.java
@@ -226,17 +226,21 @@
 	
 	@Inject
 	RoomExpressionProposalProvider expressionProposalAdapter;
+	//@Inject private DCUtil util;
 	
 	@Override
 	public void complete_CC_STRING(EObject model, RuleCall ruleCall, ContentAssistContext context, ICompletionProposalAcceptor acceptor) {
-		String text = context.getCurrentNode().getText();
-		int localOffset = context.getOffset() - context.getCurrentNode().getOffset();
-		int globalOffset = context.getOffset();
 		if (context.getCurrentNode().getSemanticElement() instanceof DetailCode) {
+			String text = context.getCurrentNode().getText();
+			int localOffset = context.getOffset() - context.getCurrentNode().getOffset();
+			int globalOffset = context.getOffset();
 			DetailCode detailCode = (DetailCode) context.getCurrentNode().getSemanticElement();
 			IDetailExpressionProvider exprPovider = UIExpressionUtil.getExpressionProvider(detailCode);
 			for(ICompletionProposal proposal : expressionProposalAdapter.createProposals(exprPovider, text, localOffset, globalOffset))
 				acceptor.accept(proposal);
+			
+			// new implementation TODO
+			//util.getProposals(context.getCurrentNode(), context.getOffset());
 		}
 
 		super.complete_CC_STRING(model, ruleCall, context, acceptor);
diff --git a/plugins/org.eclipse.etrice.core.room.ui/src/org/eclipse/etrice/core/ui/highlight/HighlightingAstVisitor.xtend b/plugins/org.eclipse.etrice.core.room.ui/src/org/eclipse/etrice/core/ui/highlight/HighlightingAstVisitor.xtend
new file mode 100644
index 0000000..f20a462
--- /dev/null
+++ b/plugins/org.eclipse.etrice.core.room.ui/src/org/eclipse/etrice/core/ui/highlight/HighlightingAstVisitor.xtend
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (c) 2011 protos software gmbh (http://www.protos.de).
+ * 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:
+ * 		Henrik Rentz-Reichert (initial contribution)
+ * 
+ *******************************************************************************/
+
+package org.eclipse.etrice.core.ui.highlight
+
+import org.eclipse.etrice.core.room.Attribute
+import org.eclipse.etrice.core.room.InterfaceItem
+import org.eclipse.etrice.core.room.MessageData
+import org.eclipse.etrice.core.room.Operation
+import org.eclipse.etrice.core.room.VarDecl
+import org.eclipse.etrice.dctools.fsm.ast.nodes.DCAstIdentifierNode
+import org.eclipse.etrice.dctools.fsm.ast.nodes.DCAstNode
+import org.eclipse.etrice.dctools.fsm.ast.nodes.DCAstOtherNode
+import org.eclipse.etrice.dctools.fsm.ast.util.IDCAstNodeVisitor
+import org.eclipse.xtext.ide.editor.syntaxcoloring.IHighlightedPositionAcceptor
+import org.eclipse.xtext.nodemodel.INode
+import org.eclipse.etrice.dctools.ast.DCUtil
+import org.eclipse.etrice.dctools.fsm.ast.nodes.DCAstOperationCallNode
+import org.eclipse.etrice.core.room.Message
+
+class HighlightingAstVisitor implements IDCAstNodeVisitor {
+	
+	IHighlightedPositionAcceptor acceptor
+	int baseOffset
+
+	static def highlight(INode node, IHighlightedPositionAcceptor acceptor, DCUtil util) {
+		val ast = util.parseAndLink(node)
+		val offset = util.getDelimiterAdjustedOffset(node)
+		val visitor = new HighlightingAstVisitor(acceptor, offset)
+		ast.visit(visitor)
+	}
+	
+	private new(IHighlightedPositionAcceptor acceptor, int baseOffset) {
+		this.acceptor = acceptor
+		this.baseOffset = baseOffset
+	}
+
+	override boolean visitBegin(DCAstNode node) {
+		var int begin
+		var int length
+		val highlightId = switch node {
+			DCAstOtherNode: {
+				begin = node.token.begin
+				length = node.token.length
+				switch node.token.token.kind {
+					case COMMENT: RoomHighlightingConfiguration.COMMENT_ID
+					case STRING: RoomHighlightingConfiguration.STRING_ID
+					case NUMBER: RoomHighlightingConfiguration.NUMBER_ID
+					case KEYWORD: RoomHighlightingConfiguration.KEYWORD_ID
+					default: null
+				}
+			}
+			DCAstIdentifierNode: {
+				begin = node.token.begin
+				length = node.token.length
+				switch DCUtil.getLinkedObject(node) {
+					Attribute,
+					MessageData,
+					VarDecl: RoomHighlightingConfiguration.HL_EXPR_ATTRIBUTE_ID
+					InterfaceItem: RoomHighlightingConfiguration.HL_EXPR_INTERFACE_ITEM_ID
+					Operation: RoomHighlightingConfiguration.HL_EXPR_OPERATION_ID
+					default: null
+				}
+			}
+			DCAstOperationCallNode: {
+				begin = node.idNode.token.begin
+				length = node.idNode.token.length
+				switch node.linkedObject {
+					Message: RoomHighlightingConfiguration.HL_EXPR_OPERATION_ID
+					default: null
+				}
+			}
+		}
+		if (highlightId !== null) {
+			acceptor.addPosition(baseOffset + begin, length, highlightId)
+		}
+		return true
+	}
+
+	override void visitEnd(DCAstNode node) {
+	}
+}
diff --git a/plugins/org.eclipse.etrice.core.room.ui/src/org/eclipse/etrice/core/ui/highlight/RoomSemanticHighlightingCalculator.java b/plugins/org.eclipse.etrice.core.room.ui/src/org/eclipse/etrice/core/ui/highlight/RoomSemanticHighlightingCalculator.java
index fff548b..8c915a7 100644
--- a/plugins/org.eclipse.etrice.core.room.ui/src/org/eclipse/etrice/core/ui/highlight/RoomSemanticHighlightingCalculator.java
+++ b/plugins/org.eclipse.etrice.core.room.ui/src/org/eclipse/etrice/core/ui/highlight/RoomSemanticHighlightingCalculator.java
@@ -15,25 +15,18 @@
 import org.eclipse.emf.ecore.EObject;
 import org.eclipse.etrice.core.common.ui.highlight.BaseSemanticHighlighter;
 import org.eclipse.etrice.core.converter.RoomValueConverterService;
-import org.eclipse.etrice.core.fsm.fSM.DetailCode;
 import org.eclipse.etrice.core.services.RoomGrammarAccess;
-import org.eclipse.etrice.core.ui.util.UIExpressionUtil;
-import org.eclipse.etrice.core.ui.util.UIExpressionUtil.ExpressionCache;
-import org.eclipse.etrice.expressions.detailcode.IDetailExpressionProvider;
-import org.eclipse.etrice.expressions.ui.highlight.ExpressionRuleFactory;
-import org.eclipse.etrice.expressions.ui.highlight.TargetLanguageRuleFactory;
-import org.eclipse.jface.text.Document;
-import org.eclipse.jface.text.rules.IRule;
-import org.eclipse.jface.text.rules.IToken;
-import org.eclipse.jface.text.rules.RuleBasedScanner;
-import org.eclipse.jface.text.rules.Token;
+import org.eclipse.etrice.dctools.ast.DCUtil;
+import org.eclipse.etrice.dctools.fsm.ast.DCLanguage;
+import org.eclipse.etrice.ui.behavior.fsm.Activator;
+import org.eclipse.etrice.ui.behavior.fsm.actioneditor.preferences.PreferenceConstants;
+import org.eclipse.jface.preference.IPreferenceStore;
 import org.eclipse.xtext.RuleCall;
 import org.eclipse.xtext.ide.editor.syntaxcoloring.IHighlightedPositionAcceptor;
 import org.eclipse.xtext.nodemodel.INode;
 import org.eclipse.xtext.resource.XtextResource;
 import org.eclipse.xtext.util.CancelIndicator;
 
-import com.google.common.collect.Iterables;
 import com.google.inject.Inject;
 
 /**
@@ -41,19 +34,24 @@
  * 
  */
 public class RoomSemanticHighlightingCalculator extends BaseSemanticHighlighter {
-
-	@Inject
-	RoomGrammarAccess grammar;
 	
-	@Inject
-	RoomValueConverterService converterService;
+	@Inject RoomGrammarAccess grammar;
+	@Inject RoomValueConverterService converterService;
+	@Inject DCUtil detailCodeUtil;
+	DCLanguage language = null;
+	
+	public RoomSemanticHighlightingCalculator() {
+	}
 	
 	@Override
 	public void provideHighlightingFor(XtextResource resource, IHighlightedPositionAcceptor acceptor, CancelIndicator cancelIndicator) {
 		if (resource == null || resource.getParseResult() == null)
 			return;
+		
+		if (language==null) {
+			setLanguage();
+		}
 
-		ExpressionCache expressionCache = new ExpressionCache();
 		INode root = resource.getParseResult().getRootNode();
 		for (INode node : root.getAsTreeIterable()) {
 			if(cancelIndicator.isCanceled()) 
@@ -68,39 +66,22 @@
 					acceptor.addPosition(node.getOffset(), node.getLength(), RoomHighlightingConfiguration.HL_ANNOTATION_ID);
 				}
 				else if(ruleCall.getRule() == grammar.getCC_STRINGRule()) {
-					detailCodeHighlight(node, acceptor, expressionCache);
+					HighlightingAstVisitor.highlight(node, acceptor, detailCodeUtil);
 				}
 			}
 
 		}
 	}
-	
-	protected void detailCodeHighlight(INode node, IHighlightedPositionAcceptor acceptor, ExpressionCache cache) {		
-		final String text = converterService.getCC_StringConverter().stripDelim(node.getText());
-		final int offset = node.getOffset() + converterService.getCC_StringConverter().getDelim().length();
-		
-		DetailCode dc = null;
-		if(node.getParent().getSemanticElement() instanceof DetailCode) {
-			dc = (DetailCode) node.getParent().getSemanticElement();
+
+	private void setLanguage() {
+		IPreferenceStore preferenceStore = Activator.getDefault().getPreferenceStore();
+		String lang = preferenceStore.getString(PreferenceConstants.EDITOR_LANGUAGE);
+		if (lang.equals(PreferenceConstants.JAVA_LANGUAGE)) {
+			language = DCLanguage.JAVA_LANGUAGE;
 		}
-		IDetailExpressionProvider exprProvider = UIExpressionUtil.getExpressionProvider(dc, null, cache);
-		XtextHighlightStyles styles = new XtextHighlightStyles();
-		RuleBasedScanner scanner = new RuleBasedScanner();
-		scanner.setRules(Iterables.toArray(Iterables.concat(
-				TargetLanguageRuleFactory.getGeneralLiteralRules(styles),
-				ExpressionRuleFactory.getInitialExpressionRules(exprProvider, styles),
-				TargetLanguageRuleFactory.getGeneralKeywordRules(styles))
-		, IRule.class));
-		scanner.setRange(new Document(text), 0, text.length());
-		
-		IToken lastToken = null;
-		while(lastToken != Token.EOF) {
-			lastToken = scanner.nextToken();
-			if(lastToken != null && lastToken.getData() != null) {
-				acceptor.addPosition(offset + scanner.getTokenOffset(), scanner.getTokenLength(), (String) lastToken.getData());
-			}
+		else {
+			language = DCLanguage.CPP_LANGUAGE;
 		}
-		
+		detailCodeUtil.setLanguage(language);
 	}
-	
 }
diff --git a/plugins/org.eclipse.etrice.core.room.ui/src/org/eclipse/etrice/core/ui/hover/RoomHoverProvider.xtend b/plugins/org.eclipse.etrice.core.room.ui/src/org/eclipse/etrice/core/ui/hover/RoomHoverProvider.xtend
index 8a0234f..1d61abc 100644
--- a/plugins/org.eclipse.etrice.core.room.ui/src/org/eclipse/etrice/core/ui/hover/RoomHoverProvider.xtend
+++ b/plugins/org.eclipse.etrice.core.room.ui/src/org/eclipse/etrice/core/ui/hover/RoomHoverProvider.xtend
@@ -13,11 +13,10 @@
 package org.eclipse.etrice.core.ui.hover
 
 import com.google.inject.Inject
-import org.eclipse.emf.ecore.EObject
 import org.eclipse.etrice.core.common.ui.hover.KeywordEObjectTextHover
 import org.eclipse.etrice.core.fsm.fSM.DetailCode
 import org.eclipse.etrice.core.services.RoomGrammarAccess
-import org.eclipse.etrice.core.ui.util.UIExpressionUtil
+import org.eclipse.etrice.dctools.ast.DCUtil
 import org.eclipse.jface.text.Region
 import org.eclipse.xtext.RuleCall
 import org.eclipse.xtext.nodemodel.util.NodeModelUtils
@@ -26,8 +25,8 @@
 
 class RoomHoverProvider extends KeywordEObjectTextHover {
 	
-	@Inject
-	RoomGrammarAccess grammar
+	@Inject RoomGrammarAccess grammar
+	@Inject DCUtil util
 	
 	override protected getXtextElementAt(XtextResource resource, int offset) {
 		// lookup expression
@@ -36,9 +35,13 @@
 			val leafNode = NodeModelUtils.findLeafNodeAtOffset(parseResult.rootNode, offset)
 			if(leafNode?.grammarElement instanceof RuleCall) {
 				if((leafNode.grammarElement as RuleCall).rule == grammar.CC_STRINGRule && leafNode.semanticElement instanceof DetailCode){
-					val exprFeature = UIExpressionUtil.findAtOffset(leafNode, offset)
-					if(exprFeature?.data instanceof EObject)
-						return Tuples.create(exprFeature.data as EObject, new Region(offset, exprFeature.id.length))
+//					println("RoomHoverProvider at offset " + offset + " " + leafNode.offset + " " + leafNode.text.substring(offset - leafNode.offset))
+					val result = util.findAtOffset(leafNode, offset)
+					if (result!==null) {
+//						val begin = result.begin
+//						println("RoomHoverProvider hit " + (leafNode.offset + result.begin) +" " + result.length + " " + leafNode.text.substring(begin, begin + result.length))
+						return Tuples.create(result.object, new Region(leafNode.offset + result.begin, result.length))
+					}
 				}
 			}
 		}
diff --git a/plugins/org.eclipse.etrice.core.room.ui/src/org/eclipse/etrice/core/ui/linking/RoomHyperlinkHelper.java b/plugins/org.eclipse.etrice.core.room.ui/src/org/eclipse/etrice/core/ui/linking/RoomHyperlinkHelper.java
index 6e2c361..c04199f 100644
--- a/plugins/org.eclipse.etrice.core.room.ui/src/org/eclipse/etrice/core/ui/linking/RoomHyperlinkHelper.java
+++ b/plugins/org.eclipse.etrice.core.room.ui/src/org/eclipse/etrice/core/ui/linking/RoomHyperlinkHelper.java
@@ -21,8 +21,8 @@
 import org.eclipse.etrice.core.room.RefSegment;
 import org.eclipse.etrice.core.room.util.RoomHelpers;
 import org.eclipse.etrice.core.services.RoomGrammarAccess;
-import org.eclipse.etrice.core.ui.util.UIExpressionUtil;
-import org.eclipse.etrice.expressions.detailcode.IDetailExpressionProvider.ExpressionFeature;
+import org.eclipse.etrice.dctools.ast.DCUtil;
+import org.eclipse.etrice.dctools.ast.DCUtil.FindResult;
 import org.eclipse.jface.text.Region;
 import org.eclipse.xtext.AbstractRule;
 import org.eclipse.xtext.RuleCall;
@@ -42,6 +42,7 @@
 
 	@Inject private RoomGrammarAccess grammar;
 	@Inject private RoomHelpers roomHelpers;
+	@Inject private DCUtil util;
 	
 	@Override
 	public void createHyperlinksByOffset(XtextResource resource, int offset, IHyperlinkAcceptor acceptor) {
@@ -67,12 +68,16 @@
 				}
 			}
 			
-			if(leaf.getGrammarElement() instanceof RuleCall) {
-				if(((RuleCall) leaf.getGrammarElement()).getRule() == grammar.getCC_STRINGRule() && leaf.getSemanticElement() instanceof DetailCode) {
-					ExpressionFeature exprFeature = UIExpressionUtil.findAtOffset(leaf, offset);
-					if(exprFeature != null && exprFeature.getData() instanceof EObject) {
-						Region region = new Region(leaf.getOffset(), leaf.getLength());
-						createHyperlinksTo(resource, region, (EObject) exprFeature.getData(), acceptor);
+			if (leaf.getGrammarElement() instanceof RuleCall) {
+				if (((RuleCall) leaf.getGrammarElement()).getRule() == grammar.getCC_STRINGRule()
+						&& leaf.getSemanticElement() instanceof DetailCode) {
+					// System.out.println("RoomHyperlinkHelper at offset " + offset + " " + leaf.getOffset() + " " + leaf.getText().substring(offset - leaf.getOffset()));
+					FindResult result = util.findAtOffset(leaf, offset);
+					if (result != null) {
+						// int begin = result.getBegin();
+						// System.out.println("RoomHyperlinkHelper hit " + (leaf.getOffset() + result.getBegin()) +" " + result.getLength() + " " + leaf.getText().substring(begin, begin + result.getLength()));
+						Region region = new Region(leaf.getOffset() + result.getBegin(), result.getLength());
+						createHyperlinksTo(resource, region, result.getObject(), acceptor);
 					}
 				}
 			}
@@ -85,12 +90,13 @@
 		ActorContainerClass lastAcContainer = roomHelpers.getParentContainer(aim);
 		ActorRef lastRef = null;
 		for (RefSegment ref : aim.getPath().getRefs()) {
-			for (ActorRef r : lastAcContainer.getActorRefs())
+			for (ActorRef r : lastAcContainer.getActorRefs()) {
 				if (r.getName().equals(ref.getRef())) {
 					lastRef = r;
 					lastAcContainer = lastRef.getType();
 					break;
 				}
+			}
 		}
 
 		return lastRef;
diff --git a/plugins/org.eclipse.etrice.dctools.fsm/src/org/eclipse/etrice/dctools/fsm/ast/CandidateMap.xtend b/plugins/org.eclipse.etrice.dctools.fsm/src/org/eclipse/etrice/dctools/fsm/ast/CandidateMap.xtend
index 178ad02..9251fd4 100644
--- a/plugins/org.eclipse.etrice.dctools.fsm/src/org/eclipse/etrice/dctools/fsm/ast/CandidateMap.xtend
+++ b/plugins/org.eclipse.etrice.dctools.fsm/src/org/eclipse/etrice/dctools/fsm/ast/CandidateMap.xtend
@@ -17,4 +17,15 @@
 
 class CandidateMap extends HashMap<String, EObject> {
 	
+	def CandidateMap getMatches(String prefix) {
+		val result = new CandidateMap
+		
+		for (entry : entrySet) {
+			if (entry.key.startsWith(prefix)) {
+				result.put(entry.key, entry.value)
+			}
+		}
+		
+		return result
+	}
 }
\ No newline at end of file
diff --git a/plugins/org.eclipse.etrice.dctools.fsm/src/org/eclipse/etrice/dctools/fsm/ast/DCNodeAtOffset.xtend b/plugins/org.eclipse.etrice.dctools.fsm/src/org/eclipse/etrice/dctools/fsm/ast/DCNodeAtOffset.xtend
new file mode 100644
index 0000000..d59d0bc
--- /dev/null
+++ b/plugins/org.eclipse.etrice.dctools.fsm/src/org/eclipse/etrice/dctools/fsm/ast/DCNodeAtOffset.xtend
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2011 protos software gmbh (http://www.protos.de).
+ * 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:
+ * 		Henrik Rentz-Reichert (initial contribution)
+ * 
+ *******************************************************************************/
+
+package org.eclipse.etrice.dctools.fsm.ast
+
+import org.eclipse.etrice.dctools.fsm.ast.util.IDCAstNodeVisitor
+import org.eclipse.etrice.dctools.fsm.ast.nodes.DCAstNode
+import org.eclipse.etrice.dctools.fsm.ast.nodes.DCAstMatchNode
+import org.eclipse.etrice.dctools.fsm.ast.nodes.DCAstTextNode
+import org.eclipse.etrice.dctools.fsm.ast.nodes.DCAstBracketNode
+
+class DCNodeAtOffset implements IDCAstNodeVisitor {
+	
+	int offset
+	DCAstTextNode result = null
+	
+	private new (int offset) {
+		this.offset = offset
+	}
+	
+	static def find(DCAstMatchNode ast, int offset) {
+		val visitor = new DCNodeAtOffset(offset)
+		ast.visit(visitor)
+		return visitor.result
+	}
+	
+	override visitBegin(DCAstNode node) {
+		if (result===null) {
+			if (node instanceof DCAstTextNode) {
+				if (node.begin<=offset && offset<node.end) {
+					result = node
+				}
+			}
+			if (node instanceof DCAstBracketNode) {
+				// also test the closing bracket
+				if (node.posClose>=0) {
+					if (node.posClose==offset) {
+						result = node
+					}
+				}
+			}
+		}
+		return result===null
+	}
+	
+	override visitEnd(DCAstNode node) {
+	}
+	
+}
\ No newline at end of file
diff --git a/plugins/org.eclipse.etrice.dctools.fsm/src/org/eclipse/etrice/dctools/fsm/ast/DCParser.xtend b/plugins/org.eclipse.etrice.dctools.fsm/src/org/eclipse/etrice/dctools/fsm/ast/DCParser.xtend
index 4eaa047..0a190c8 100644
--- a/plugins/org.eclipse.etrice.dctools.fsm/src/org/eclipse/etrice/dctools/fsm/ast/DCParser.xtend
+++ b/plugins/org.eclipse.etrice.dctools.fsm/src/org/eclipse/etrice/dctools/fsm/ast/DCParser.xtend
@@ -166,19 +166,21 @@
 				var b = token.token as DCBracketToken
 				if (b.bracketKind==left) {
 					val contents = Match(parent)
+					val leftPos = token.begin
 					token = read
 					if (token!==null) {
 						if (token.token instanceof DCBracketToken) {
+							val rightPos = token.begin
 							b = token.token as DCBracketToken
 							if (b.bracketKind==right) {
-								return new DCAstBracketNode(parent, type, contents)
+								return new DCAstBracketNode(parent, type, contents, leftPos, rightPos)
 							}
 						}
 						unread // second token
 					}
 					else {
 						// we reached the end without a matching right bracket
-						return new DCAstBracketNode(parent, type, contents, false)
+						return new DCAstBracketNode(parent, type, contents, leftPos)
 					}
 					unread(contents)
 				}
@@ -203,7 +205,7 @@
 			var token = read
 			while (token!==null) {
 				if (token.token.kind==Kind.PERIOD) {
-					val pNode = new DCAstPeriodNode(null)
+					val pNode = new DCAstPeriodNode(null, token.begin)
 					val wsNode = Whitespace(null)
 					val cNode = Call(null)
 					val wsNode2 = Whitespace(null)
@@ -327,7 +329,7 @@
 		
 		if (count>0) {
 			val ws = text.substring(begin, end)
-			return new DCAstWhitespaceNode(parent, count, ws)
+			return new DCAstWhitespaceNode(parent, count, begin, ws)
 		}
 		
 		return null
diff --git a/plugins/org.eclipse.etrice.dctools.fsm/src/org/eclipse/etrice/dctools/fsm/ast/internal/DCSpecialCharRule.xtend b/plugins/org.eclipse.etrice.dctools.fsm/src/org/eclipse/etrice/dctools/fsm/ast/internal/DCSpecialCharRule.xtend
index 09fa428..2169be9 100644
--- a/plugins/org.eclipse.etrice.dctools.fsm/src/org/eclipse/etrice/dctools/fsm/ast/internal/DCSpecialCharRule.xtend
+++ b/plugins/org.eclipse.etrice.dctools.fsm/src/org/eclipse/etrice/dctools/fsm/ast/internal/DCSpecialCharRule.xtend
@@ -20,12 +20,12 @@
 
 class DCSpecialCharRule implements IRule {
 	
+	public static val char SEP = ';'
+	public static val char PERIOD = '.'
+	
 	val period = new DCToken(Kind.PERIOD)
 	val sep = new DCToken(Kind.STATEMENT_SEP)
 	
-	val char SEP = ';'
-	val char PERIOD = '.'
-	
 	override evaluate(ICharacterScanner scanner) {
 		val c = scanner.read as char
 		
diff --git a/plugins/org.eclipse.etrice.dctools.fsm/src/org/eclipse/etrice/dctools/fsm/ast/nodes/DCAstBracketNode.xtend b/plugins/org.eclipse.etrice.dctools.fsm/src/org/eclipse/etrice/dctools/fsm/ast/nodes/DCAstBracketNode.xtend
index 99a2bcc..660f8f6 100644
--- a/plugins/org.eclipse.etrice.dctools.fsm/src/org/eclipse/etrice/dctools/fsm/ast/nodes/DCAstBracketNode.xtend
+++ b/plugins/org.eclipse.etrice.dctools.fsm/src/org/eclipse/etrice/dctools/fsm/ast/nodes/DCAstBracketNode.xtend
@@ -16,7 +16,7 @@
 import org.eclipse.xtend.lib.annotations.Accessors
 
 @Accessors
-class DCAstBracketNode extends DCAstNode {
+class DCAstBracketNode extends DCAstTextNode {
 	
 	enum BracketType {
 		ROUND,
@@ -25,22 +25,24 @@
 	}
 	
 	BracketType type
+	int posClose
 	boolean closed
 	
-	new(DCAstNode parent, BracketType type, DCAstNode contents) {
-		this(parent, type, contents, true)
-	}
-	
-	new(DCAstNode parent, BracketType type, DCAstNode contents, boolean closed) {
-		super(parent, 2)
+	new(DCAstNode parent, BracketType type, DCAstNode contents, int posOpen, int posClose) {
+		super(parent, 2, posOpen, posOpen+1)
 		this.type = type
-		this.closed = closed
+		this.posClose = posClose
+		this.closed = posClose>=0
 		
 		if (contents!==null) {
 			contents.parent = this
 		}
 	}
 	
+	new(DCAstNode parent, BracketType type, DCAstNode contents, int posOpen) {
+		this(parent, type, contents, posOpen, -1)
+	}
+	
 	def left() {
 		switch type {
 			case CURLY: "{"
@@ -69,4 +71,5 @@
 		println(indent + "DCAstBracketNode " + this.toString)
 	}
 	
+	override def String getText() { toString }
 }
\ No newline at end of file
diff --git a/plugins/org.eclipse.etrice.dctools.fsm/src/org/eclipse/etrice/dctools/fsm/ast/nodes/DCAstIdentifierBracketNode.xtend b/plugins/org.eclipse.etrice.dctools.fsm/src/org/eclipse/etrice/dctools/fsm/ast/nodes/DCAstIdentifierBracketNode.xtend
index 94d5d31..51c69e5 100644
--- a/plugins/org.eclipse.etrice.dctools.fsm/src/org/eclipse/etrice/dctools/fsm/ast/nodes/DCAstIdentifierBracketNode.xtend
+++ b/plugins/org.eclipse.etrice.dctools.fsm/src/org/eclipse/etrice/dctools/fsm/ast/nodes/DCAstIdentifierBracketNode.xtend
@@ -33,7 +33,7 @@
 	}
 	
 	def String id() {
-		idNode.identifier
+		idNode.id
 	}
 	
 	def String ws() {
diff --git a/plugins/org.eclipse.etrice.dctools.fsm/src/org/eclipse/etrice/dctools/fsm/ast/nodes/DCAstIdentifierNode.xtend b/plugins/org.eclipse.etrice.dctools.fsm/src/org/eclipse/etrice/dctools/fsm/ast/nodes/DCAstIdentifierNode.xtend
index 84c932d..b330891 100644
--- a/plugins/org.eclipse.etrice.dctools.fsm/src/org/eclipse/etrice/dctools/fsm/ast/nodes/DCAstIdentifierNode.xtend
+++ b/plugins/org.eclipse.etrice.dctools.fsm/src/org/eclipse/etrice/dctools/fsm/ast/nodes/DCAstIdentifierNode.xtend
@@ -16,19 +16,21 @@
 import org.eclipse.xtend.lib.annotations.Accessors
 
 @Accessors
-class DCAstIdentifierNode extends DCAstNode {
+class DCAstIdentifierNode extends DCAstTextNode {
 	
-	String identifier
+	String id
 	DCTextToken token
 	
-	new(DCAstNode parent, String identifier, DCTextToken token) {
-		super(parent, 1)
-		this.identifier = identifier
+	new(DCAstNode parent, String id, DCTextToken token) {
+		super(parent, 1, token.begin, token.begin+token.length)
+		this.id = id
 		this.token = token
 	}
 	
 	override protected doPrint(String indent) {
-		println(indent + "DCAstIdentifierNode '" + identifier + "'" + linkedObjectText)
+		println(indent + "DCAstIdentifierNode '" + id + "'" + linkedObjectText)
 	}
 	
+	override getText() { id }
+	
 }
\ No newline at end of file
diff --git a/plugins/org.eclipse.etrice.dctools.fsm/src/org/eclipse/etrice/dctools/fsm/ast/nodes/DCAstOtherNode.xtend b/plugins/org.eclipse.etrice.dctools.fsm/src/org/eclipse/etrice/dctools/fsm/ast/nodes/DCAstOtherNode.xtend
index 1ebd193..ee93222 100644
--- a/plugins/org.eclipse.etrice.dctools.fsm/src/org/eclipse/etrice/dctools/fsm/ast/nodes/DCAstOtherNode.xtend
+++ b/plugins/org.eclipse.etrice.dctools.fsm/src/org/eclipse/etrice/dctools/fsm/ast/nodes/DCAstOtherNode.xtend
@@ -16,13 +16,13 @@
 import org.eclipse.xtend.lib.annotations.Accessors
 
 @Accessors
-class DCAstOtherNode extends DCAstNode {
+class DCAstOtherNode extends DCAstTextNode {
 	
 	String text
 	DCTextToken token
 	
 	new(DCAstNode parent, String text, DCTextToken token) {
-		super(parent, 1)
+		super(parent, 1, token.begin, token.begin+token.length)
 		this.text = text
 		this.token = token
 	}
diff --git a/plugins/org.eclipse.etrice.dctools.fsm/src/org/eclipse/etrice/dctools/fsm/ast/nodes/DCAstPeriodNode.xtend b/plugins/org.eclipse.etrice.dctools.fsm/src/org/eclipse/etrice/dctools/fsm/ast/nodes/DCAstPeriodNode.xtend
index 535d401..a29d353 100644
--- a/plugins/org.eclipse.etrice.dctools.fsm/src/org/eclipse/etrice/dctools/fsm/ast/nodes/DCAstPeriodNode.xtend
+++ b/plugins/org.eclipse.etrice.dctools.fsm/src/org/eclipse/etrice/dctools/fsm/ast/nodes/DCAstPeriodNode.xtend
@@ -13,14 +13,17 @@
 package org.eclipse.etrice.dctools.fsm.ast.nodes
 
 import org.eclipse.etrice.dctools.fsm.ast.nodes.DCAstNode
+import org.eclipse.etrice.dctools.fsm.ast.internal.DCSpecialCharRule
 
-class DCAstPeriodNode extends DCAstNode {
+class DCAstPeriodNode extends DCAstTextNode {
 	
-	new(DCAstNode parent) {
-		super(parent, 1)
+	new(DCAstNode parent, int pos) {
+		super(parent, 1, pos, pos+1)
 	}
 	
 	override protected doPrint(String indent) {
 		println(indent + "DCAstPeriodNode")
 	}
+	
+	override String getText() { String.valueOf(DCSpecialCharRule.PERIOD) }
 }
\ No newline at end of file
diff --git a/plugins/org.eclipse.etrice.dctools.fsm/src/org/eclipse/etrice/dctools/fsm/ast/nodes/DCAstTextNode.xtend b/plugins/org.eclipse.etrice.dctools.fsm/src/org/eclipse/etrice/dctools/fsm/ast/nodes/DCAstTextNode.xtend
new file mode 100644
index 0000000..c008b35
--- /dev/null
+++ b/plugins/org.eclipse.etrice.dctools.fsm/src/org/eclipse/etrice/dctools/fsm/ast/nodes/DCAstTextNode.xtend
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2011 protos software gmbh (http://www.protos.de).
+ * 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:
+ * 		Henrik Rentz-Reichert (initial contribution)
+ * 
+ *******************************************************************************/
+
+package org.eclipse.etrice.dctools.fsm.ast.nodes
+
+import org.eclipse.xtend.lib.annotations.Accessors
+
+@Accessors
+abstract class DCAstTextNode extends DCAstNode {
+	
+	int begin
+	int end
+	
+	new(DCAstNode parent, int readTokens, int begin, int end) {
+		super(parent, readTokens)
+		this.begin = begin
+		this.end = end
+	}
+	
+	abstract def String getText()
+}
\ No newline at end of file
diff --git a/plugins/org.eclipse.etrice.dctools.fsm/src/org/eclipse/etrice/dctools/fsm/ast/nodes/DCAstWhitespaceNode.xtend b/plugins/org.eclipse.etrice.dctools.fsm/src/org/eclipse/etrice/dctools/fsm/ast/nodes/DCAstWhitespaceNode.xtend
index c001777..1ff691f 100644
--- a/plugins/org.eclipse.etrice.dctools.fsm/src/org/eclipse/etrice/dctools/fsm/ast/nodes/DCAstWhitespaceNode.xtend
+++ b/plugins/org.eclipse.etrice.dctools.fsm/src/org/eclipse/etrice/dctools/fsm/ast/nodes/DCAstWhitespaceNode.xtend
@@ -16,16 +16,18 @@
 import org.eclipse.xtend.lib.annotations.Accessors
 
 @Accessors
-class DCAstWhitespaceNode extends DCAstNode {
+class DCAstWhitespaceNode extends DCAstTextNode {
 	
 	String text
 	
-	new(DCAstNode parent, int readTokens, String text) {
-		super(parent, readTokens)
+	new(DCAstNode parent, int readTokens, int pos, String text) {
+		super(parent, readTokens, pos, pos+text.length)
 		this.text = text
 	}
 	
 	override protected doPrint(String indent) {
 		println(indent + "DCAstWhitespaceNode '" + text + "'")
 	}
+	
+	override getText() { text }
 }
\ No newline at end of file
diff --git a/plugins/org.eclipse.etrice.dctools.fsm/src/org/eclipse/etrice/dctools/fsm/ast/util/DCAstPrinter.xtend b/plugins/org.eclipse.etrice.dctools.fsm/src/org/eclipse/etrice/dctools/fsm/ast/util/DCAstPrinter.xtend
index d5e7435..7811910 100644
--- a/plugins/org.eclipse.etrice.dctools.fsm/src/org/eclipse/etrice/dctools/fsm/ast/util/DCAstPrinter.xtend
+++ b/plugins/org.eclipse.etrice.dctools.fsm/src/org/eclipse/etrice/dctools/fsm/ast/util/DCAstPrinter.xtend
@@ -31,7 +31,7 @@
 		
 		switch node {
 			DCAstBracketNode: sb.append(node.left)
-			DCAstIdentifierNode: sb.append(node.identifier)
+			DCAstIdentifierNode: sb.append(node.id)
 			DCAstPeriodNode: sb.append(".")
 			DCAstWhitespaceNode: sb.append(node.text)
 			DCAstOtherNode: sb.append(node.text)
diff --git a/plugins/org.eclipse.etrice.dctools/META-INF/MANIFEST.MF b/plugins/org.eclipse.etrice.dctools/META-INF/MANIFEST.MF
index 809caa3..f5a1bf9 100644
--- a/plugins/org.eclipse.etrice.dctools/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.etrice.dctools/META-INF/MANIFEST.MF
@@ -8,12 +8,16 @@
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Require-Bundle: com.google.guava,
  org.eclipse.emf.ecore,
+ org.eclipse.jface.text,
  org.eclipse.xtext.xbase.lib,
  org.eclipse.xtend.lib,
  org.eclipse.xtend.lib.macro,
+ org.eclipse.xtext.ui,
  org.eclipse.etrice.core.fsm,
  org.eclipse.etrice.core.room,
  org.eclipse.etrice.dctools.fsm;visibility:=reexport,
- org.eclipse.etrice.generator.fsm
-Export-Package: org.eclipse.etrice.dctools.ast
+ org.eclipse.etrice.generator.fsm,
+ org.eclipse.etrice.core.genmodel.fsm
+Export-Package: org.eclipse.etrice.dctools,
+ org.eclipse.etrice.dctools.ast
 
diff --git a/plugins/org.eclipse.etrice.dctools/src/org/eclipse/etrice/dctools/GenModelAccess.xtend b/plugins/org.eclipse.etrice.dctools/src/org/eclipse/etrice/dctools/GenModelAccess.xtend
new file mode 100644
index 0000000..340b069
--- /dev/null
+++ b/plugins/org.eclipse.etrice.dctools/src/org/eclipse/etrice/dctools/GenModelAccess.xtend
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2011 protos software gmbh (http://www.protos.de).
+ * 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:
+ * 		Henrik Rentz-Reichert (initial contribution)
+ * 
+ *******************************************************************************/
+
+package org.eclipse.etrice.dctools
+
+import java.util.Map
+import org.eclipse.etrice.core.RoomStandaloneSetup
+import org.eclipse.etrice.core.fsm.fSM.ModelComponent
+import org.eclipse.etrice.core.genmodel.fsm.ExtendedFsmGenBuilder
+import org.eclipse.etrice.core.genmodel.fsm.fsmgen.GraphContainer
+
+class GenModelAccess {
+	
+		Map<ModelComponent, GraphContainer> cache = newHashMap
+		
+		def public GraphContainer get(ModelComponent mc) {
+			if(!cache.containsKey(mc)) {
+				val injector = new RoomStandaloneSetup().createInjector
+				val builder = new ExtendedFsmGenBuilder(injector);
+				val gc = builder.createTransformedModel(mc)
+				builder.withCommonData(gc)
+				cache.put(mc, gc)
+			}
+			
+			return cache.get(mc)
+		}
+}
\ No newline at end of file
diff --git a/plugins/org.eclipse.etrice.dctools/src/org/eclipse/etrice/dctools/ast/DCLinker.xtend b/plugins/org.eclipse.etrice.dctools/src/org/eclipse/etrice/dctools/ast/DCLinker.xtend
index 30ea98b..d703ea1 100644
--- a/plugins/org.eclipse.etrice.dctools/src/org/eclipse/etrice/dctools/ast/DCLinker.xtend
+++ b/plugins/org.eclipse.etrice.dctools/src/org/eclipse/etrice/dctools/ast/DCLinker.xtend
@@ -99,20 +99,21 @@
 	}
 	
 	protected def dispatch void link(DCAstIdentifierNode node) {
-		val candidates = getCandidates(FeatureType.SCALAR)
-		node.linkedObject = candidates.get(node.identifier)
-		replaceContext(node.linkedObject)
+		node.doLink(FeatureType.SCALAR, node.id)
 	}
 	
 	protected def dispatch void link(DCAstArrayAccessNode node) {
-		val candidates = getCandidates(FeatureType.ARRAY)
-		node.linkedObject = candidates.get(node.id)
-		replaceContext(node.linkedObject)
+		node.doLink(FeatureType.ARRAY, node.id)
 	}
 	
 	protected def dispatch void link(DCAstOperationCallNode node) {
-		val candidates = getCandidates(FeatureType.OPERATION)
-		node.linkedObject = candidates.get(node.id)
+		node.doLink(FeatureType.OPERATION, node.id)
+	}
+	
+	protected def void doLink(DCAstNode node, FeatureType ft, String name) {
+		val candidates = getCandidates(ft)
+		node.linkedObject = candidates.get(name)
+		node.linkedData = candidates
 		replaceContext(node.linkedObject)
 	}
 	
diff --git a/plugins/org.eclipse.etrice.dctools/src/org/eclipse/etrice/dctools/ast/DCUtil.xtend b/plugins/org.eclipse.etrice.dctools/src/org/eclipse/etrice/dctools/ast/DCUtil.xtend
new file mode 100644
index 0000000..e2f5809
--- /dev/null
+++ b/plugins/org.eclipse.etrice.dctools/src/org/eclipse/etrice/dctools/ast/DCUtil.xtend
@@ -0,0 +1,148 @@
+/*******************************************************************************
+ * Copyright (c) 2011 protos software gmbh (http://www.protos.de).
+ * 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:
+ * 		Henrik Rentz-Reichert (initial contribution)
+ * 
+ *******************************************************************************/
+
+package org.eclipse.etrice.dctools.ast
+
+import com.google.inject.Inject
+import java.util.List
+import org.eclipse.emf.ecore.EObject
+import org.eclipse.etrice.core.converter.RoomValueConverterService
+import org.eclipse.etrice.core.fsm.fSM.DetailCode
+import org.eclipse.etrice.core.fsm.fSM.TransitionBase
+import org.eclipse.etrice.core.genmodel.fsm.FsmGenExtensions
+import org.eclipse.etrice.core.room.ActorClass
+import org.eclipse.etrice.core.room.MessageData
+import org.eclipse.etrice.core.room.RoomClass
+import org.eclipse.etrice.dctools.GenModelAccess
+import org.eclipse.etrice.dctools.ast.internal.DCProposalConfig
+import org.eclipse.etrice.dctools.fsm.ast.CandidateMap
+import org.eclipse.etrice.dctools.fsm.ast.DCLanguage
+import org.eclipse.etrice.dctools.fsm.ast.DCNodeAtOffset
+import org.eclipse.etrice.dctools.fsm.ast.DCParser
+import org.eclipse.etrice.dctools.fsm.ast.nodes.DCAstIdentifierNode
+import org.eclipse.jface.text.contentassist.ICompletionProposal
+import org.eclipse.xtend.lib.annotations.Accessors
+import org.eclipse.xtext.EcoreUtil2
+import org.eclipse.xtext.nodemodel.ILeafNode
+import org.eclipse.xtext.nodemodel.INode
+
+class DCUtil {
+	
+	@Accessors
+	static class FindResult {
+		val EObject object
+		val int begin
+		val int length
+	}
+	
+	@Inject RoomValueConverterService converterService
+	@Inject DCProposalConfig proposalConfig
+	
+	val genModelAccess = new GenModelAccess
+	DCLanguage language = DCLanguage.C_LANGUAGE
+	
+	new() {
+	}
+	
+	def setLanguage(DCLanguage language) {
+		this.language = language
+	}
+	
+	def FindResult findAtOffset(ILeafNode textNode, int offset) {
+		val ast = textNode.parseAndLink
+		val astNode = DCNodeAtOffset.find(ast, offset - textNode.delimiterAdjustedOffset)
+		if (astNode instanceof DCAstIdentifierNode) {
+			val object = getLinkedObject(astNode)
+			if (object !==null) {
+				return new FindResult(object, astNode.begin + converterService.CC_StringConverter.delim.length, astNode.end-astNode.begin)
+			}
+		}
+		return null
+	}
+	
+	def getDelimiterAdjustedOffset(INode astNode) {
+		astNode.offset + converterService.CC_StringConverter.delim.length
+	}
+	
+	def parseAndLink(INode astNode) {
+		val text = converterService.CC_StringConverter.stripDelim(astNode.getText());
+		val parser = new DCParser(language)
+		val ast = parser.parse(text)
+		
+		if (astNode.parent.semanticElement instanceof DetailCode) {
+			val dc = astNode.parent.semanticElement as DetailCode
+			
+			var DCLinker linker = null;
+			
+			// lets check whether we have a transition and determine common data
+			val transition = EcoreUtil2.getContainerOfType(dc, TransitionBase)
+			if (transition!==null) {
+				val roomClass = EcoreUtil2.getContainerOfType(dc, RoomClass)
+				if (roomClass instanceof ActorClass) {
+					val gc = genModelAccess.get(roomClass)
+					val link = FsmGenExtensions.getLinkFor(gc, transition)
+					if (link!==null) {
+						linker = new DCLinker(dc, link.commonData as MessageData)
+					}
+				}
+			}
+			
+			// if we have no common data we use a plain linker
+			if (linker===null) {
+				linker = new DCLinker(dc)
+			}
+			
+			ast.visit(linker)
+			
+			return ast
+		}
+		else {
+			return null
+		}
+	}
+	
+	def List<ICompletionProposal> getProposals(INode textNode, int offset) {
+		val ast = textNode.parseAndLink
+		// note: we subtract 1 to get the token to the left of the caret
+		val astNode = DCNodeAtOffset.find(ast, offset - textNode.delimiterAdjustedOffset - 1)
+		if (astNode instanceof DCAstIdentifierNode) {
+			val candidates = astNode.candidates
+			if (candidates!==null) {
+				val begin = astNode.begin + converterService.CC_StringConverter.delim.length
+				val end = offset - textNode.offset
+				val prefix = textNode.text.substring(begin, end)
+				val matches = candidates.getMatches(prefix)
+				return matches.entrySet.map[match | proposalConfig.doCreateProposal(prefix, match.key, match.value, offset)].toList
+			}
+		}
+		
+		newArrayList
+	}
+	
+	static def EObject getLinkedObject(DCAstIdentifierNode astNode) {
+		if (astNode.linkedObject!==null) {
+			astNode.linkedObject
+		}
+		else if (astNode.parent!==null) {
+			astNode.parent.linkedObject
+		}
+	}
+	
+	static def CandidateMap getCandidates(DCAstIdentifierNode astNode) {
+		if (astNode.linkedData instanceof CandidateMap) {
+			astNode.linkedData as CandidateMap
+		}
+		else if (astNode.parent!==null && astNode.parent.linkedData instanceof CandidateMap) {
+			astNode.parent.linkedData as CandidateMap
+		}
+	}
+}
diff --git a/plugins/org.eclipse.etrice.dctools/src/org/eclipse/etrice/dctools/ast/internal/DCProposalConfig.xtend b/plugins/org.eclipse.etrice.dctools/src/org/eclipse/etrice/dctools/ast/internal/DCProposalConfig.xtend
new file mode 100644
index 0000000..8f28887
--- /dev/null
+++ b/plugins/org.eclipse.etrice.dctools/src/org/eclipse/etrice/dctools/ast/internal/DCProposalConfig.xtend
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * Copyright (c) 2011 protos software gmbh (http://www.protos.de).
+ * 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:
+ * 		Henrik Rentz-Reichert (initial contribution)
+ * 
+ *******************************************************************************/
+
+package org.eclipse.etrice.dctools.ast.internal
+
+import com.google.inject.Singleton
+import com.google.inject.Inject
+import org.eclipse.jface.viewers.ILabelProvider
+import org.eclipse.etrice.core.room.util.RoomHelpers
+import org.eclipse.emf.ecore.EObject
+import org.eclipse.jface.viewers.StyledString
+import org.eclipse.swt.graphics.Image
+import org.eclipse.xtext.ui.editor.contentassist.ConfigurableCompletionProposal
+import org.eclipse.xtext.ui.editor.contentassist.PrefixMatcher
+import org.eclipse.jface.text.contentassist.ICompletionProposal
+import org.eclipse.swt.graphics.Point
+import org.eclipse.etrice.core.room.Operation
+import org.eclipse.etrice.core.room.Message
+import org.eclipse.etrice.core.room.Attribute
+import org.eclipse.etrice.core.room.InterfaceItem
+import org.eclipse.etrice.core.room.Port
+
+@Singleton
+class DCProposalConfig {
+
+	@Inject
+	protected ILabelProvider labelProvider
+
+	@Inject
+	protected RoomHelpers roomHelpers
+	
+	@Inject
+	protected PrefixMatcher prefixMatcher
+	
+	def ICompletionProposal doCreateProposal(String prefix, String proposal, EObject object, int globalOffset) {
+		new ConfigurableCompletionProposal(proposal, globalOffset - prefix.length, prefix.length, proposal.length, object.image, object.displayString, null, null) => [
+			matcher = prefixMatcher
+			autoInsertable = false
+			// TODO adjust length to existing text
+			replaceContextLength = proposal.length
+		]
+	}
+
+	def Pair<String, Point> getPostfixReplacement(EObject object) {
+		val brackets = switch object {
+			Operation,
+			Message:
+				#['(', ')']
+			
+			Attribute case object.size>0,
+			Port case object.multiplicity>0:
+				#['[', ']']
+		}
+		
+		if (brackets===null) {
+			return "" -> null
+		}
+		
+		val replacement = switch object {
+			Operation:
+				object.arguments.map[name].join(', ')
+			
+			Message case object.data !== null:
+				object.data.refType.type.name
+			
+			Attribute, // fall through
+			InterfaceItem:
+				'0'
+			
+			default:
+				''
+		}
+
+		replacement.wrap(brackets.head, brackets.last)
+	}
+	
+	private def Pair<String, Point> wrap(String text, String left, String right) {
+		val selection = if (!text.empty) new Point(1, text.length)
+		left + text + right -> selection
+	}
+	
+	private def StyledString getDisplayString(EObject object) {
+		
+	}	
+
+	private def Image getImage(EObject object) {
+		
+	}	
+}
\ No newline at end of file
diff --git a/plugins/org.eclipse.etrice.dctools/src/org/eclipse/etrice/dctools/ast/internal/DCTranslatorVisitor.xtend b/plugins/org.eclipse.etrice.dctools/src/org/eclipse/etrice/dctools/ast/internal/DCTranslatorVisitor.xtend
index afd514a..c307273 100644
--- a/plugins/org.eclipse.etrice.dctools/src/org/eclipse/etrice/dctools/ast/internal/DCTranslatorVisitor.xtend
+++ b/plugins/org.eclipse.etrice.dctools/src/org/eclipse/etrice/dctools/ast/internal/DCTranslatorVisitor.xtend
@@ -62,7 +62,7 @@
 		else {
 			if (!node.skipOutput) {
 				switch node {
-					DCAstIdentifierNode: currentSB.append(node.identifier)
+					DCAstIdentifierNode: currentSB.append(node.id)
 					DCAstPeriodNode: currentSB.append(".")
 					DCAstWhitespaceNode: currentSB.append(node.text)
 					DCAstOtherNode: currentSB.append(node.text)
@@ -159,7 +159,7 @@
 		val translated =
 			if (ifItemNode instanceof DCAstIdentifierNode) {
 				// accessed as scalar (means broadcast for replicated port)
-				val inst = ifItemNode.identifier
+				val inst = ifItemNode.id
 				translationProvider.getInterfaceItemMessageText(ifItem, msg, inst, args, null, msgNode.originalText)
 			}
 			else if (ifItemNode instanceof DCAstArrayAccessNode) {
diff --git a/tests/org.eclipse.etrice.dctools.tests/src/org/eclipse/etrice/dctools/tests/TestConstants.xtend b/tests/org.eclipse.etrice.dctools.tests/src/org/eclipse/etrice/dctools/tests/TestConstants.xtend
index 8a38916..34894c5 100644
--- a/tests/org.eclipse.etrice.dctools.tests/src/org/eclipse/etrice/dctools/tests/TestConstants.xtend
+++ b/tests/org.eclipse.etrice.dctools.tests/src/org/eclipse/etrice/dctools/tests/TestConstants.xtend
@@ -32,7 +32,7 @@
 	static val TEST_MEMBER_ACCESS = "field.member"
 	static val TEST_ARRAY_MEMBER_ACCESS = "field[1+2].member"
 	static val TEST_ARRAY_MEMBER_ACCESS_AND_CALL = TEST_ARRAY_MEMBER_ACCESS + ".op()"
-	static val TEST_SPACY_ARRAY_MEMBER_ACCESS_AND_CALL = "field [ 1 + 2 ]\n\t. member . op ( )"
+	static val TEST_SPACIOUS_ARRAY_MEMBER_ACCESS_AND_CALL = "field [ 1 + 2 ]\n\t. member . op ( )"
 	static val TEST_CODE = "DC var = new DC(); port.message(var);"
 	static val TEST_CODE1 = "field.member1.member2[3].operation(x+4)"
 	static val TEST_CODE2 = '''
diff --git a/tests/org.eclipse.etrice.dctools.tests/src/org/eclipse/etrice/dctools/tests/TestDCNodeAtOffset.xtend b/tests/org.eclipse.etrice.dctools.tests/src/org/eclipse/etrice/dctools/tests/TestDCNodeAtOffset.xtend
new file mode 100644
index 0000000..6b52257
--- /dev/null
+++ b/tests/org.eclipse.etrice.dctools.tests/src/org/eclipse/etrice/dctools/tests/TestDCNodeAtOffset.xtend
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ * Copyright (c) 2011 protos software gmbh (http://www.protos.de).
+ * 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:
+ * 		Henrik Rentz-Reichert (initial contribution)
+ * 
+ *******************************************************************************/
+
+package org.eclipse.etrice.dctools.tests
+
+import org.eclipse.etrice.dctools.fsm.ast.DCParser
+import org.junit.Before
+import org.eclipse.etrice.dctools.fsm.ast.DCLanguage
+import static org.eclipse.etrice.dctools.tests.TestConstants.*
+import org.junit.Test
+import org.eclipse.etrice.dctools.fsm.ast.DCNodeAtOffset
+import static org.junit.Assert.*
+import static org.hamcrest.CoreMatchers.*
+import org.eclipse.etrice.dctools.fsm.ast.nodes.DCAstOtherNode
+import org.eclipse.etrice.dctools.fsm.ast.nodes.DCAstIdentifierNode
+import org.eclipse.etrice.dctools.fsm.ast.nodes.DCAstBracketNode
+
+class TestDCNodeAtOffset {
+		
+	DCParser parser
+	
+	@Before
+	def void createParser() {
+		parser = new DCParser(DCLanguage.C_LANGUAGE)
+	}
+	
+	@Test
+	def void testString() {
+		val ast = parser.parse(TEST_STRING)
+		val result = DCNodeAtOffset.find(ast, 3)
+		assertNotNull(result)
+		assertTrue(result instanceof DCAstOtherNode)
+		assertThat(result.text, is(TEST_STRING))
+	}
+	
+	@Test
+	def void testMemberAccess() {
+		val ast = parser.parse(TEST_MEMBER_ACCESS)
+		var result = DCNodeAtOffset.find(ast, 8)
+		assertNotNull(result)
+		assertTrue(result instanceof DCAstIdentifierNode)
+		assertThat(result.text, is("member"))
+
+		result = DCNodeAtOffset.find(ast, 4)
+		assertNotNull(result)
+		assertTrue(result instanceof DCAstIdentifierNode)
+		assertThat(result.text, is("field"))
+	}
+	
+	@Test
+	def void testArrayMemberAccess() {
+		val ast = parser.parse(TEST_ARRAY_MEMBER_ACCESS)
+		var result = DCNodeAtOffset.find(ast, 14)
+		assertNotNull(result)
+		assertTrue(result instanceof DCAstIdentifierNode)
+		assertThat(result.text, is("member"))
+
+		result = DCNodeAtOffset.find(ast, 4)
+		assertNotNull(result)
+		assertTrue(result instanceof DCAstIdentifierNode)
+		assertThat(result.text, is("field"))
+
+		result = DCNodeAtOffset.find(ast, 7)
+		assertNotNull(result)
+		assertTrue(result instanceof DCAstOtherNode)
+		assertThat(result.text, is("+"))
+	}
+	
+	@Test
+	def void testCode() {
+		val ast = parser.parse(TEST_CODE)
+		var result = DCNodeAtOffset.find(ast, 16)
+		assertNotNull(result)
+		assertTrue(result instanceof DCAstBracketNode)
+		if (result instanceof DCAstBracketNode) {
+			assertThat(result.text, is("()"))
+			assertThat(result.begin, is(15))
+			assertThat(result.end, is(16))
+			assertThat(result.posClose, is(16))
+		}
+	}
+	
+	@Test
+	def void testCode2() {
+		val ast = parser.parse(TEST_CODE2)
+		
+		// note: because line breaks differ on UNIX and Windows we can't use a constant offset here
+		val pos = TEST_CODE2.indexOf("456")+2
+		
+		var result = DCNodeAtOffset.find(ast, pos)
+		assertNotNull(result)
+		assertTrue(result instanceof DCAstOtherNode)
+		assertThat(result.text, is("456"))
+	}
+}
diff --git a/tests/org.eclipse.etrice.dctools.tests/src/org/eclipse/etrice/dctools/tests/TestDCParser.xtend b/tests/org.eclipse.etrice.dctools.tests/src/org/eclipse/etrice/dctools/tests/TestDCParser.xtend
index df0e392..b9e9449 100644
--- a/tests/org.eclipse.etrice.dctools.tests/src/org/eclipse/etrice/dctools/tests/TestDCParser.xtend
+++ b/tests/org.eclipse.etrice.dctools.tests/src/org/eclipse/etrice/dctools/tests/TestDCParser.xtend
@@ -149,7 +149,7 @@
 		// it is an identifier node
 		node = node.children.get(0)
 		assertTrue(node instanceof DCAstIdentifierNode)
-		assertThat((node as DCAstIdentifierNode).identifier, is(TEST_IDENTIFIER))
+		assertThat((node as DCAstIdentifierNode).id, is(TEST_IDENTIFIER))
 		
 		prettyPrint("testIdentifier", TEST_IDENTIFIER, result, 1, 3)
 	}
@@ -257,11 +257,11 @@
 	}
 	
 	@Test
-	def void testSpacyArrayMemberAccessAndCall() {
-		val result = parser.parse(TEST_SPACY_ARRAY_MEMBER_ACCESS_AND_CALL)
+	def void testSpaciousArrayMemberAccessAndCall() {
+		val result = parser.parse(TEST_SPACIOUS_ARRAY_MEMBER_ACCESS_AND_CALL)
 		assertNotNull(result)
 		
-		prettyPrint("testSpacyArrayMemberAccessAndCall", TEST_SPACY_ARRAY_MEMBER_ACCESS_AND_CALL, result, 23, 27)
+		prettyPrint("testSpacyArrayMemberAccessAndCall", TEST_SPACIOUS_ARRAY_MEMBER_ACCESS_AND_CALL, result, 23, 27)
 	}
 	
 	@Test
diff --git a/tests/org.eclipse.etrice.dctools.tests/src/org/eclipse/etrice/dctools/tests/TestDCScanner.xtend b/tests/org.eclipse.etrice.dctools.tests/src/org/eclipse/etrice/dctools/tests/TestDCScanner.xtend
index 8f164b5..f28da31 100644
--- a/tests/org.eclipse.etrice.dctools.tests/src/org/eclipse/etrice/dctools/tests/TestDCScanner.xtend
+++ b/tests/org.eclipse.etrice.dctools.tests/src/org/eclipse/etrice/dctools/tests/TestDCScanner.xtend
@@ -166,8 +166,8 @@
 	}
 	
 	@Test
-	def void testSpacyArrayMemberAccessAndCall() {
-		val tokens = scanner.scan(TEST_SPACY_ARRAY_MEMBER_ACCESS_AND_CALL)
+	def void testSpaciousArrayMemberAccessAndCall() {
+		val tokens = scanner.scan(TEST_SPACIOUS_ARRAY_MEMBER_ACCESS_AND_CALL)
 		assertThat(tokens.size, is(23))
 		
 		var pos = 0