public void Init()
		{
			HostCallback.GetCurrentProjectContent = delegate {
				return ParserService.CurrentProjectContent;
			};
			
			ef = new VBNetExpressionFinder(null);
		}
		public CodeCompletionKeyPressResult HandleKeyPress(ITextEditor editor, char ch)
		{
			if (IsInComment(editor) || IsInString(editor))
				return CodeCompletionKeyPressResult.None;
			
			if (editor.SelectionLength > 0) {
				// allow code completion when overwriting an identifier
				int endOffset = editor.SelectionStart + editor.SelectionLength;
				// but block code completion when overwriting only part of an identifier
				if (endOffset < editor.Document.TextLength && char.IsLetterOrDigit(editor.Document.GetCharAt(endOffset)))
					return CodeCompletionKeyPressResult.None;
				
				editor.Document.Remove(editor.SelectionStart, editor.SelectionLength);
			}
			
			VBNetExpressionFinder ef = new VBNetExpressionFinder(ParserService.GetParseInformation(editor.FileName));
			
			ExpressionResult result;
			
			switch (ch) {
				case '(':
					if (CodeCompletionOptions.InsightEnabled) {
						IInsightWindow insightWindow = editor.ShowInsightWindow(new MethodInsightProvider().ProvideInsight(editor));
						if (insightWindow != null) {
							insightHandler.InitializeOpenedInsightWindow(editor, insightWindow);
							insightHandler.HighlightParameter(insightWindow, 0);
							insightWindow.CaretPositionChanged += delegate { Run(insightWindow, editor); };
						}
						return CodeCompletionKeyPressResult.Completed;
					}
					break;
				case ',':
					if (CodeCompletionOptions.InsightRefreshOnComma && CodeCompletionOptions.InsightEnabled) {
						IInsightWindow insightWindow;
						editor.Document.Insert(editor.Caret.Offset, ",");
						if (insightHandler.InsightRefreshOnComma(editor, ch, out insightWindow)) {
							if (insightWindow != null) {
								insightHandler.HighlightParameter(insightWindow, GetArgumentIndex(editor) + 1);
								insightWindow.CaretPositionChanged += delegate { Run(insightWindow, editor); };;
							}
						}
						return CodeCompletionKeyPressResult.EatKey;
					}
					break;
				case '\n':
					TryDeclarationTypeInference(editor, editor.Document.GetLineForOffset(editor.Caret.Offset));
					break;
				case '.':
					string w = editor.GetWordBeforeCaret(); int index = w.IndexOf('.');
					
					if (index > -1 && w.Length - index == 2)
						index = editor.Caret.Offset - 2;
					else
						index = editor.Caret.Offset;
					
					result = ef.FindExpression(editor.Document.Text, index);
					LoggingService.Debug("CC: After dot, result=" + result + ", context=" + result.Context);
					ShowCompletion(result, editor, ch);
					return CodeCompletionKeyPressResult.Completed;
				case '@':
					if (editor.Caret.Offset > 0 && editor.Document.GetCharAt(editor.Caret.Offset - 1) == '.')
						return CodeCompletionKeyPressResult.None;
					goto default;
				case ' ':
					editor.Document.Insert(editor.Caret.Offset, " ");
					result = ef.FindExpression(editor.Document.Text, editor.Caret.Offset);
					
					string word = editor.GetWordBeforeCaret().Trim();
					if (word.Equals("overrides", StringComparison.OrdinalIgnoreCase) || word.Equals("return", StringComparison.OrdinalIgnoreCase) || !LiteralMayFollow((BitArray)result.Tag) && !OperatorMayFollow((BitArray)result.Tag) && ExpressionContext.IdentifierExpected != result.Context) {
						LoggingService.Debug("CC: After space, result=" + result + ", context=" + result.Context);
						ShowCompletion(result, editor, ch);
					}
					return CodeCompletionKeyPressResult.EatKey;
				default:
					if (CodeCompletionOptions.CompleteWhenTyping) {
						int cursor = editor.Caret.Offset;
						char prevChar = cursor > 1 ? editor.Document.GetCharAt(cursor - 1) : ' ';
						char ppChar = cursor > 2 ? editor.Document.GetCharAt(cursor - 2) : ' ';
						
						result = ef.FindExpression(editor.Document.Text, cursor);
						
						if ((result.Context != ExpressionContext.IdentifierExpected && char.IsLetter(ch)) &&
						    (!char.IsLetterOrDigit(prevChar) && prevChar != '.')) {
							if (prevChar == '@' && ppChar == '.')
								return CodeCompletionKeyPressResult.None;
							if (IsTypeCharacter(ch, prevChar))
								return CodeCompletionKeyPressResult.None;
							LoggingService.Debug("CC: Beginning to type a word, result=" + result + ", context=" + result.Context);
							ShowCompletion(result, editor, ch);
							return CodeCompletionKeyPressResult.CompletedIncludeKeyInCompletion;
						}
					}
					break;
			}
			
			return CodeCompletionKeyPressResult.None;
		}
		public bool CtrlSpace(ITextEditor editor)
		{
			if (IsInComment(editor))
				return false;
			
			if (editor.SelectionLength > 0) {
				// allow code completion when overwriting an identifier
				int endOffset = editor.SelectionStart + editor.SelectionLength;
				// but block code completion when overwriting only part of an identifier
				if (endOffset < editor.Document.TextLength && char.IsLetterOrDigit(editor.Document.GetCharAt(endOffset)))
					return false;
				
				editor.Document.Remove(editor.SelectionStart, editor.SelectionLength);
			}
			
			int cursor = editor.Caret.Offset;
			char prevChar = cursor > 1 ? editor.Document.GetCharAt(cursor - 1) : ' ';
			bool afterUnderscore = prevChar == '_';
			
			if (afterUnderscore) {
				cursor--;
				prevChar = cursor > 1 ? editor.Document.GetCharAt(cursor - 1) : ' ';
			}
			
			VBNetExpressionFinder ef = new VBNetExpressionFinder(ParserService.GetParseInformation(editor.FileName));
			ExpressionResult result = ef.FindExpression(editor.Document.Text, cursor);
			LoggingService.Debug("CC: Beginning to type a word, result=" + result + ", context=" + result.Context);
			ShowCompletion(result, editor, '\0');
			return true;
		}