[MonoDevelop] Removing SourceEditor{View, Buffer} dependancy from CompletionListWindow.

Peter Johanson latexer at gentoo.org
Tue Jul 19 21:31:39 EDT 2005


On Tue, Jul 19, 2005 at 10:52:02AM +0200, Lluis Sanchez wrote:
> Hi,
> 
> The patch looks like a good start. Here are some comments:
> 
>       * prepareCompletionDetails -> PrepareCompletionDetails
> 
>       * You should avoid using a property like ICompletionWidget.Text.
>         Loading the entire file text in memory is a bad practice. I know
>         we are doing it in other places but it shouldn't be done. In
>         most of cases you can use methods such as for example: string
>         GetText (int startOffset, int endOffset).
> 
>       * Methods in TextUtilities should take a ICompletionWidget as
>         parameter and use its methods to get the text it needs. The same
>         for ICompletionDataProvider, TemplateCompletionDataProvider and
>         CommentCompletionDataProvider.
> 
>       * Please give more meaningful names to ICompletionWidget
>         properties (what does X and Y refer to?). 
> 
>       * ICompletionData.InsertAction should also take a
>         ICompletionWidget as parameter. 
> 
>       * CompletionWindow.cs is obsolete, it can be removed. 
> 

Ok, attached are two new versions of the patches implementing the points
above. Further thoughts?

-pete


-- 
Peter Johanson
<latexer at gentoo.org>
-------------- next part --------------
Index: Core/src/MonoDevelop.Base/Services/ParserService/DefaultParserService.cs
===================================================================
--- Core/src/MonoDevelop.Base/Services/ParserService/DefaultParserService.cs	(revision 2671)
+++ Core/src/MonoDevelop.Base/Services/ParserService/DefaultParserService.cs	(working copy)
@@ -255,8 +255,6 @@
 			IProjectService projectService = Runtime.ProjectService;
 			projectService.CombineOpened += new CombineEventHandler(OnCombineOpened);
 			projectService.CombineClosed += new CombineEventHandler(OnCombineClosed);
-			projectService.ReferenceAddedToProject += new ProjectReferenceEventHandler (OnProjectReferencesChanged);
-			projectService.ReferenceRemovedFromProject += new ProjectReferenceEventHandler (OnProjectReferencesChanged);
 		}
 		
 		internal IProgressMonitor GetParseProgressMonitor ()
@@ -367,6 +365,8 @@
 					GetDatabase (re.Uri);
 
 				project.NameChanged += new CombineEntryRenamedEventHandler (OnProjectRenamed);
+				project.ReferenceAddedToProject += new ProjectReferenceEventHandler (OnProjectReferencesChanged);
+				project.ReferenceRemovedFromProject += new ProjectReferenceEventHandler (OnProjectReferencesChanged);
 			}
 		}
 		
@@ -389,6 +389,8 @@
 			string uri = "Project:" + project.Name;
 			UnloadDatabase (uri);
 			project.NameChanged -= new CombineEntryRenamedEventHandler (OnProjectRenamed);
+			project.ReferenceAddedToProject -= new ProjectReferenceEventHandler (OnProjectReferencesChanged);
+			project.ReferenceRemovedFromProject -= new ProjectReferenceEventHandler (OnProjectReferencesChanged);
 		}
 		
 		void CleanUnusedDatabases ()
Index: Core/src/MonoDevelop.Base/Gui/Completion/ICompletionWidget.cs
===================================================================
--- Core/src/MonoDevelop.Base/Gui/Completion/ICompletionWidget.cs	(revision 0)
+++ Core/src/MonoDevelop.Base/Gui/Completion/ICompletionWidget.cs	(revision 0)
@@ -0,0 +1,32 @@
+
+using System;
+using MonoDevelop.Internal.Project;
+using Gtk;
+
+namespace MonoDevelop.Gui.Completion
+{
+
+	public interface ICompletionWidget
+	{
+		string Text { get; }
+		int TextLength { get; }
+		string GetText (int startOffset, int endOffset);
+		char GetChar (int offset);
+
+		string CompletionText { get; }
+
+		void SetCompletionText (string partial_word, string complete_word);
+
+		void InsertAtCursor (string text);
+
+		int TriggerOffset { get; }
+		int TriggerLine { get; }
+		int TriggerLineOffset { get; }
+
+		int TriggerXCoord { get; }
+		int TriggerYCoord { get; }
+		int TriggerTextHeight { get; }
+
+		Gtk.Style GtkStyle { get; }
+	}
+}
Index: Core/src/MonoDevelop.Base/Makefile.am
===================================================================
--- Core/src/MonoDevelop.Base/Makefile.am	(revision 2671)
+++ Core/src/MonoDevelop.Base/Makefile.am	(working copy)
@@ -87,6 +87,7 @@
 Gui/Components/SdMenuCheckBox.cs \
 Gui/Components/SdMenuCommand.cs \
 Gui/Components/SdToolbarCommand.cs \
+Gui/Completion/ICompletionWidget.cs \
 Gui/WorkbenchWindowCollection.cs \
 Gui/WorkbenchSingleton.cs \
 Gui/IMementoCapable.cs \
Index: Core/src/AddIns/DisplayBindings/SourceEditor/Gui/SourceEditorView.cs
===================================================================
--- Core/src/AddIns/DisplayBindings/SourceEditor/Gui/SourceEditorView.cs	(revision 2671)
+++ Core/src/AddIns/DisplayBindings/SourceEditor/Gui/SourceEditorView.cs	(working copy)
@@ -10,6 +10,7 @@
 using MonoDevelop.Core.AddIns;
 using MonoDevelop.Internal.Templates;
 using MonoDevelop.Internal.Parser;
+using MonoDevelop.Internal.Project;
 using MonoDevelop.Core.Services;
 using MonoDevelop.SourceEditor.CodeCompletion;
 using MonoDevelop.SourceEditor.InsightWindow;
@@ -17,6 +18,7 @@
 using MonoDevelop.EditorBindings.FormattingStrategy;
 using MonoDevelop.Gui.Utils;
 using MonoDevelop.Gui;
+using MonoDevelop.Gui.Completion;
 using MonoDevelop.Services;
 using MonoDevelop.Commands;
 using MonoDevelop.DefaultEditor;
@@ -25,7 +27,7 @@
 
 namespace MonoDevelop.SourceEditor.Gui
 {
-	public class SourceEditorView : SourceView, IFormattableDocument
+	public class SourceEditorView : SourceView, IFormattableDocument, ICompletionWidget
 	{	
 		public readonly SourceEditor ParentEditor;
 		internal IFormattingStrategy fmtr;
@@ -194,8 +196,8 @@
 				return;
 			triggerIter.ForwardChar ();
 			
-//			CompletionWindow.ShowWindow (triggerChar, triggerIter, true, new CodeCompletionDataProvider (true), this);
-			CompletionListWindow.ShowWindow (triggerChar, triggerIter, new CodeCompletionDataProvider (true), this);
+			PrepareCompletionDetails(triggerIter);
+			CompletionListWindow.ShowWindow (triggerChar, new CodeCompletionDataProvider (true), this, this.ParentEditor.DisplayBinding.Project, this.ParentEditor.DisplayBinding.ContentName);
 		}
 
 		bool MonodocResolver ()
@@ -375,8 +377,8 @@
 			case '.':
 				bool retval = base.OnKeyPressEvent (evnt);
 				if (EnableCodeCompletion && PeekCharIsWhitespace ()) {
-//					CompletionWindow.ShowWindow ((char)key, buf.GetIterAtMark (buf.InsertMark), false, new CodeCompletionDataProvider (), this);
-					CompletionListWindow.ShowWindow ((char)key, buf.GetIterAtMark (buf.InsertMark), new CodeCompletionDataProvider (), this);
+					PrepareCompletionDetails(buf.GetIterAtMark (buf.InsertMark));
+					CompletionListWindow.ShowWindow ((char)key, new CodeCompletionDataProvider (), this, this.ParentEditor.DisplayBinding.Project, this.ParentEditor.DisplayBinding.ContentName);
 				}
 				return retval;
 				/*case '(':
@@ -582,6 +584,20 @@
 			end.ForwardToLineEnd ();
 			Buffer.MoveMark ("selection_bound", end);
 		}
+
+		void PrepareCompletionDetails(TextIter iter)
+		{
+			Gdk.Rectangle rect = GetIterLocation (Buffer.GetIterAtMark (Buffer.InsertMark));
+			int wx, wy;
+			BufferToWindowCoords (Gtk.TextWindowType.Widget, rect.X, rect.Y + rect.Height, out wx, out wy);
+			int tx, ty;
+			GdkWindow.GetOrigin (out tx, out ty);
+
+			this.completionX = tx + wx;
+			this.completionY = ty + wy;
+			this.textHeight = rect.Height;
+			this.triggerMark = buf.CreateMark (null, iter, true);
+		}
 #endregion
 
 #region IFormattableDocument
@@ -661,7 +677,118 @@
 			offset = begin.Offset;
 			len = begin.CharsInLine;
 		}
+#endregion
 
+#region ICompletionWidget
+
+		private int completionX;
+		int ICompletionWidget.TriggerXCoord
+		{
+			get
+			{
+				return completionX;
+			}
+		}
+
+		private int completionY;
+		int ICompletionWidget.TriggerYCoord
+		{
+			get
+			{
+				return completionY;
+			}
+		}
+
+		private int textHeight;
+		int ICompletionWidget.TriggerTextHeight
+		{
+			get
+			{
+				return textHeight;
+			}
+		}
+
+		string ICompletionWidget.CompletionText
+		{
+			get
+			{
+				return Buffer.GetText (Buffer.GetIterAtMark (triggerMark), Buffer.GetIterAtMark (Buffer.InsertMark), false);
+			}
+		}
+
+		void ICompletionWidget.SetCompletionText (string partial_word, string complete_word)
+		{
+			TextIter offsetIter = buf.GetIterAtMark(triggerMark);
+                        TextIter endIter = buf.GetIterAtOffset (offsetIter.Offset + partial_word.Length);
+                        buf.MoveMark (buf.InsertMark, offsetIter);
+                        buf.Delete (ref offsetIter, ref endIter);
+                        buf.InsertAtCursor (complete_word);
+		}
+
+		void ICompletionWidget.InsertAtCursor (string text)
+		{
+			buf.InsertAtCursor (text);
+		}
+		
+		string ICompletionWidget.Text
+		{
+			get
+			{
+				return buf.Text;
+			}
+		}
+
+		int ICompletionWidget.TextLength
+		{
+			get
+			{
+				return buf.EndIter.Offset + 1;
+			}
+		}
+
+		char ICompletionWidget.GetChar (int offset)
+		{
+			return buf.GetIterAtOffset (offset).Char[0];
+		}
+
+		string ICompletionWidget.GetText (int startOffset, int endOffset)
+		{
+			return buf.GetText(buf.GetIterAtOffset (startOffset), buf.GetIterAtOffset(endOffset), true);
+		}
+
+		private TextMark triggerMark;
+		int ICompletionWidget.TriggerOffset
+		{
+			get
+			{
+				return buf.GetIterAtMark (triggerMark).Offset;
+			}
+		}
+
+		int ICompletionWidget.TriggerLine
+		{
+			get
+			{
+				return buf.GetIterAtMark (triggerMark).Line;
+			}
+		}
+
+		int ICompletionWidget.TriggerLineOffset
+		{
+			get
+			{
+				return buf.GetIterAtMark (triggerMark).LineOffset;
+			}
+		}
+
+		Gtk.Style ICompletionWidget.GtkStyle
+		{
+			get
+			{
+				return Style.Copy();
+			}
+		}
+
 		bool PeekCharIsWhitespace ()
 		{
 			TextIter start = buf.GetIterAtMark (buf.InsertMark);
Index: Core/src/AddIns/DisplayBindings/SourceEditor/InsightWindow/IndexerInsightDataProvider.cs
===================================================================
--- Core/src/AddIns/DisplayBindings/SourceEditor/InsightWindow/IndexerInsightDataProvider.cs	(revision 2671)
+++ Core/src/AddIns/DisplayBindings/SourceEditor/InsightWindow/IndexerInsightDataProvider.cs	(working copy)
@@ -17,6 +17,8 @@
 using MonoDevelop.Internal.Parser;
 using MonoDevelop.Internal.Project;
 
+using MonoDevelop.Gui.Completion;
+
 using MonoDevelop.SourceEditor.Gui;
 using MonoDevelop.SourceEditor.CodeCompletion;
 
Index: Core/src/AddIns/DisplayBindings/SourceEditor/CodeCompletion/ICompletionData.cs
===================================================================
--- Core/src/AddIns/DisplayBindings/SourceEditor/CodeCompletion/ICompletionData.cs	(revision 2671)
+++ Core/src/AddIns/DisplayBindings/SourceEditor/CodeCompletion/ICompletionData.cs	(working copy)
@@ -10,6 +10,8 @@
 using System.Reflection;
 using System.Collections;
 
+using MonoDevelop.Gui.Completion;
+
 using MonoDevelop.SourceEditor.Gui;
 
 namespace MonoDevelop.SourceEditor.CodeCompletion
@@ -33,7 +35,7 @@
 			get;
 		}
 		
-		void InsertAction(SourceEditorView control);
+		void InsertAction(ICompletionWidget widget);
 	}
 	
 	public interface ICompletionDataWithMarkup : ICompletionData
Index: Core/src/AddIns/DisplayBindings/SourceEditor/CodeCompletion/CompletionListWindow.cs
===================================================================
--- Core/src/AddIns/DisplayBindings/SourceEditor/CodeCompletion/CompletionListWindow.cs	(revision 2671)
+++ Core/src/AddIns/DisplayBindings/SourceEditor/CodeCompletion/CompletionListWindow.cs	(working copy)
@@ -5,6 +5,7 @@
 using MonoDevelop.SourceEditor.Gui;
 using MonoDevelop.Internal.Project;
 using MonoDevelop.Gui;
+using MonoDevelop.Gui.Completion;
 
 namespace MonoDevelop.SourceEditor.CodeCompletion
 {
@@ -12,8 +13,7 @@
 	{
 		string fileName;
 		Project project;
-		SourceEditorView control;
-		TextMark triggeringMark;
+		ICompletionWidget completionWidget;
 		ICompletionData[] completionData;
 		DeclarationViewWindow declarationviewwindow = new DeclarationViewWindow ();
 		static DataComparer dataComparer = new DataComparer ();
@@ -40,14 +40,13 @@
 			SizeAllocated += new SizeAllocatedHandler (ListSizeChanged);
 		}
 		
-		public static void ShowWindow (char firstChar, TextIter trigIter, ICompletionDataProvider provider, SourceEditorView ctrl)
+		public static void ShowWindow (char firstChar, ICompletionDataProvider provider, ICompletionWidget completionWidget, Project project, string fileName)
 		{
-			if (!wnd.ShowListWindow (firstChar, trigIter, provider,  ctrl))
+			if (!wnd.ShowListWindow (firstChar, provider,  completionWidget, project, fileName))
 				return;
 			
 			// makes control-space in midle of words to work
-			TextBuffer buf = wnd.control.Buffer; 
-			string text = buf.GetText (trigIter, buf.GetIterAtMark (buf.InsertMark), false);
+			string text = wnd.completionWidget.CompletionText;
 			if (text.Length == 0)
 				return;
 			
@@ -63,32 +62,25 @@
 			wnd.PartialWord = wnd.CompleteWord;		
 		}
 		
-		bool ShowListWindow (char firstChar, TextIter trigIter, ICompletionDataProvider provider, SourceEditorView ctrl)
+		bool ShowListWindow (char firstChar, ICompletionDataProvider provider, ICompletionWidget completionWidget, Project project, string fileName)
 		{
-			this.control = ctrl;
-			this.fileName = ctrl.ParentEditor.DisplayBinding.ContentName;
-			this.project = ctrl.ParentEditor.DisplayBinding.Project;
-			triggeringMark = control.Buffer.CreateMark (null, trigIter, true);
+			this.completionWidget = completionWidget;
+			this.fileName = fileName;
+			this.project = project;
 			
-			completionData = provider.GenerateCompletionData (project, fileName, ctrl, firstChar, triggeringMark);
+			completionData = provider.GenerateCompletionData (project, fileName, completionWidget, firstChar);
+
 			if (completionData == null || completionData.Length == 0) return false;
 			
-			this.Style = ctrl.Style.Copy();
+			this.Style = completionWidget.GtkStyle;
 			
 			Array.Sort (completionData, dataComparer);
 			
 			DataProvider = this;
-			Gdk.Rectangle rect = control.GetIterLocation (control.Buffer.GetIterAtMark (triggeringMark));
 
-			int wx, wy;
-			control.BufferToWindowCoords (Gtk.TextWindowType.Widget, rect.X /*+ rect.Width*/, rect.Y + rect.Height, out wx, out wy);
+			int x = completionWidget.TriggerXCoord;
+			int y = completionWidget.TriggerYCoord;
 			
-			int tx, ty;
-			control.GdkWindow.GetOrigin (out tx, out ty);
-			
-			int x = tx + wx;
-			int y = ty + wy;
-			
 			int w, h;
 			GetSize (out w, out h);
 			
@@ -96,8 +88,10 @@
 				x = Screen.Width - w;
 			
 			if ((y + h) > Screen.Height)
-				y = y - rect.Height - h;
-							
+			{
+				y = y - completionWidget.TriggerTextHeight - h;
+			}
+
 			Move (x, y);
 			
 			Show ();
@@ -140,11 +134,7 @@
 		
 		void UpdateWord ()
 		{
-			TextIter offsetIter = wnd.control.Buffer.GetIterAtMark (wnd.triggeringMark);
-			TextIter endIter = wnd.control.Buffer.GetIterAtOffset (offsetIter.Offset + wnd.PartialWord.Length);
-			wnd.control.Buffer.MoveMark (wnd.control.Buffer.InsertMark, offsetIter);
-			wnd.control.Buffer.Delete (ref offsetIter, ref endIter);
-			wnd.control.Buffer.InsertAtCursor (wnd.CompleteWord);
+			completionWidget.SetCompletionText(wnd.PartialWord, wnd.CompleteWord);
 		}
 		
 		public new void Hide ()
Index: Core/src/AddIns/DisplayBindings/SourceEditor/CodeCompletion/CodeCompletionData.cs
===================================================================
--- Core/src/AddIns/DisplayBindings/SourceEditor/CodeCompletion/CodeCompletionData.cs	(revision 2671)
+++ Core/src/AddIns/DisplayBindings/SourceEditor/CodeCompletion/CodeCompletionData.cs	(working copy)
@@ -14,6 +14,7 @@
 
 using MonoDevelop.Internal.Parser;
 using MonoDevelop.Services;
+using MonoDevelop.Gui.Completion;
 using MonoDevelop.Core.Services;
 using MonoDevelop.SourceEditor.Gui;
 
@@ -219,9 +220,9 @@
 			documentation = "";
 		}
 		
-		public void InsertAction (SourceEditorView control)
+		public void InsertAction (ICompletionWidget widget)
 		{
-			control.Buffer.InsertAtCursor (completionString);
+			widget.InsertAtCursor (completionString);
 		}
 
 		public static string GetDocumentation (string doc)
Index: Core/src/AddIns/DisplayBindings/SourceEditor/CodeCompletion/TextUtilities.cs
===================================================================
--- Core/src/AddIns/DisplayBindings/SourceEditor/CodeCompletion/TextUtilities.cs	(revision 2671)
+++ Core/src/AddIns/DisplayBindings/SourceEditor/CodeCompletion/TextUtilities.cs	(working copy)
@@ -8,6 +8,7 @@
 using System;
 using System.Text;
 using System.Diagnostics;
+using MonoDevelop.Gui.Completion;
 using MonoDevelop.SourceEditor.Gui;
 
 namespace MonoDevelop.SourceEditor.CodeCompletion
@@ -74,23 +75,21 @@
 		/// That method is used in code completion to determine the expression given
 		/// to the parser for type resolve.
 		/// </remarks>
-		public static string GetExpressionBeforeOffset(SourceEditorView textArea, int offset)
+		//public static string GetExpressionBeforeOffset(string text, int offset)
+		public static string GetExpressionBeforeOffset(ICompletionWidget widget, int offset)
 		{
-			// FIXME: we should actually use GtkTextIter's
-			string text = textArea.Buffer.Text;
 			int origOffset = offset;
 			
 			while (offset - 1 > 0) {
-				switch (text [offset - 1]) {
+				switch (widget.GetChar (offset - 1)) {
 					case '}':
 						goto done;
-//						offset = SearchBracketBackward(document, offset - 2, '{','}');
 //						break;
 					case ']':
-						offset = SearchBracketBackward(textArea, offset - 2, '[',']');
+						offset = SearchBracketBackward(widget, offset - 2, '[',']');
 						break;
 					case ')':
-						offset = SearchBracketBackward(textArea, offset - 2, '(',')');
+						offset = SearchBracketBackward(widget, offset - 2, '(',')');
 						break;
 					case '.':
 						--offset;
@@ -100,30 +99,28 @@
 					case '\'':
 						return "'a'";
 					case '>':
-						if (text [offset - 2] == '-') {
+						if (widget.GetChar (offset - 2) == '-') {
 							offset -= 2;
 							break;
 						}
 						goto done;
 					default:
-						if (Char.IsWhiteSpace (text [offset - 1])) {
+						if (Char.IsWhiteSpace (widget.GetChar (offset - 1))) {
 							--offset;
 							break;
 						}
 						int start = offset - 1;
-						if (!IsLetterDigitOrUnderscore (text [start])) {
+						if (!IsLetterDigitOrUnderscore (widget.GetChar (start))) {
 							goto done;
 						}
 						
-						while (start > 0 && IsLetterDigitOrUnderscore (text[start - 1])) {
+						while (start > 0 && IsLetterDigitOrUnderscore (widget.GetChar(start - 1))) {
 							--start;
 						}
 						
-						//Console.WriteLine("{0} -- {1}", offset, start);
-						Gtk.TextIter startIter = textArea.Buffer.GetIterAtOffset (start);
-						Gtk.TextIter endIter = textArea.Buffer.GetIterAtOffset (offset);
-						string word = textArea.Buffer.GetText (startIter, endIter, false).Trim();
-						//Console.WriteLine("word >{0}<", word);
+						Console.WriteLine("{0} -- {1}", offset, start);
+						string word = widget.GetText (start, offset);
+						Console.WriteLine("word >{0}<", word);
 						switch (word) {
 							case "ref":
 							case "out":
@@ -142,11 +139,8 @@
 				}
 			}
 			done:
-//			Console.WriteLine("ofs : {0} cart:{1}", offset, document.Caret.Offset);
-//			Console.WriteLine("return:" + document.GetText(offset, document.Caret.Offset - offset).Trim());
-			Gtk.TextIter start_Iter = textArea.Buffer.GetIterAtOffset (origOffset);
-			Gtk.TextIter offset_Iter = textArea.Buffer.GetIterAtOffset (offset);
-			return textArea.Buffer.GetText (start_Iter, offset_Iter, false ).Trim();
+//			Console.WriteLine("offset : {0} origOffset: {1}", offset, origOffset);
+			return offset - origOffset > 0 ? widget.GetText(origOffset, offset).Trim() : "";
 		}
 		
 /*		
@@ -244,18 +238,16 @@
 			return document.GetText(line.Offset, line.Length);
 		}
 */
-		static bool ScanLineComment(SourceEditorView document, int offset)
+		static bool ScanLineComment(ICompletionWidget widget, int offset)
 		{
-			// FIXME: use iters
-			string text = document.Buffer.Text;
-			while (offset > 0 && offset < text.Length) {
-				char ch = text [offset];
+			while (offset > 0 && offset < widget.TextLength) {
+				char ch = widget.GetChar (offset);
 				switch (ch) {
 					case '\r':
 					case '\n':
 						return false;
 					case '/':
-						if (text[offset + 1] == '/') {
+						if (widget.GetChar (offset + 1) == '/') {
 							return true;
 						}
 						break;
@@ -265,47 +257,46 @@
 			return false;
 		}
 		
-		public static int SearchBracketBackward(SourceEditorView document, int offset, char openBracket, char closingBracket)
+		public static int SearchBracketBackward(ICompletionWidget widget, int offset, char openBracket, char closingBracket)
 		{
 			// FIXME: use iters
-			string text = document.Buffer.Text;			
 			int brackets = -1;		
 			bool inString = false;
 			bool inChar   = false;	
 			bool blockComment = false;
 			
-			while (offset >= 0 && offset < text.Length) {
-				char ch = text [offset];
+			while (offset >= 0 && offset < widget.TextLength) {
+				char ch = widget.GetChar(offset);
 				switch (ch) {
 					case '/':
 						if (blockComment) {
-							if (text [offset + 1]== '*') {
+							if (widget.GetChar(offset + 1)== '*') {
 								blockComment = false;
 							}
 						}
-						if (!inString && !inChar && offset + 1 < text.Length) {
-							if (offset > 0 && text [offset - 1] == '*') {
+						if (!inString && !inChar && offset + 1 < widget.TextLength) {
+							if (offset > 0 && widget.GetChar(offset - 1) == '*') {
 								blockComment = true;
 							}
 						}
 						break;
 					case '"':
-						if (!inChar && !blockComment && !ScanLineComment(document, offset)) {
+						if (!inChar && !blockComment && !ScanLineComment(widget, offset)) {
 							inString = !inString;
 						}
 						break;
 					case '\'':
-						if (!inString && !blockComment && !ScanLineComment(document, offset)) {
+						if (!inString && !blockComment && !ScanLineComment(widget, offset)) {
 							inChar = !inChar;
 						}
 						break;
 					default :
 						if (ch == closingBracket) {
-							if (!(inString || inChar || blockComment) && !ScanLineComment(document, offset)) {
+							if (!(inString || inChar || blockComment) && !ScanLineComment(widget, offset)) {
 								--brackets;
 							}
 						} else if (ch == openBracket) {
-							if (!(inString || inChar || blockComment) && !ScanLineComment(document, offset)) {
+							if (!(inString || inChar || blockComment) && !ScanLineComment(widget, offset)) {
 								++brackets;
 								if (brackets == 0) {
 									return offset;
Index: Core/src/AddIns/DisplayBindings/SourceEditor/CodeCompletion/CompletionWindow.cs
===================================================================
--- Core/src/AddIns/DisplayBindings/SourceEditor/CodeCompletion/CompletionWindow.cs	(revision 2671)
+++ Core/src/AddIns/DisplayBindings/SourceEditor/CodeCompletion/CompletionWindow.cs	(working copy)
@@ -1,427 +0,0 @@
-// <file>
-//     <copyright see="prj:///doc/copyright.txt"/>
-//     <license see="prj:///doc/license.txt"/>
-//     <owner name="Mike Kr??ger" email="mike at icsharpcode.net"/>
-//     <version value="$version"/>
-// </file>
-
-using System;
-using System.Drawing;
-using System.Collections;
-
-using Gtk;
-using MonoDevelop.SourceEditor.Gui;
-using MonoDevelop.Internal.Project;
-using MonoDevelop.Gui;
-
-namespace MonoDevelop.SourceEditor.CodeCompletion
-{
-	public class CompletionWindow : Window
-	{
-		const  int  DeclarationIndent  = 1;
-		TreeViewColumn complete_column;
-		
-		ICompletionDataProvider completionDataProvider;
-		SourceEditorView control;
-		TreeView listView;
-		ListStore store;
-		TextMark triggeringMark;
-		int origOffset;
-		int num_in = 0;
-		DeclarationViewWindow declarationviewwindow = new DeclarationViewWindow ();
-		string fileName;
-		Project project;
-
-		static CompletionWindow wnd;
-
-		static CompletionWindow ()
-		{
-			wnd = new CompletionWindow ();
-		}
-		
-		string GetTypedString ()
-		{
-			TextIter startIter = control.Buffer.GetIterAtMark (control.Buffer.InsertMark);
-			TextIter offsetIter = control.Buffer.GetIterAtMark (triggeringMark);
-			return control.Buffer.GetText (offsetIter, startIter, true);
-		}
-
-		int insertLength {
-			get {
-				TextIter startIter = control.Buffer.GetIterAtMark (control.Buffer.InsertMark);
-				return startIter.Offset - origOffset;
-			}
-		}
-
-		void DeleteInsertion()
-		{
-			TextIter startIter = control.Buffer.GetIterAtMark (control.Buffer.InsertMark);
-			TextIter offsetIter = control.Buffer.GetIterAtMark (triggeringMark);
-			if (startIter.Offset > offsetIter.Offset) {
-				int newPos = offsetIter.Offset;
-				control.Buffer.Delete (ref offsetIter, ref startIter);
-				control.Buffer.MoveMark (control.Buffer.InsertMark, control.Buffer.GetIterAtOffset (newPos));
-			}
-		}
-
-		protected override bool OnKeyPressEvent (Gdk.EventKey e)
-		{
-			uint state = (uint)e.State;
-			state &= 1101u;
-
-			switch (state) {
-			case 0: //NORMAL
-				switch ((char)e.Key) {
-				case '.':
-				case ' ':
-				case ';':
-				case '(':
-				case '[':
-				case ',':
-					control.SimulateKeyPress (ref e);
-					LostFocusListView (null, null);
-					return true;
-					
-				case (char) Gdk.Key.Return:
-				case (char) Gdk.Key.ISO_Enter:
-				case (char) Gdk.Key.Key_3270_Enter:
-				case (char) Gdk.Key.KP_Enter:
-					KeyPressEventArgs fake_args = new KeyPressEventArgs ();
-					fake_args.Args = new object[] { e };
-					ListKeypressEvent (null, fake_args);
-					return true;
-					
-				case (char) Gdk.Key.BackSpace:
-					num_in--;
-					control.SimulateKeyPress (ref e);
-					if (insertLength <= -1) {
-						LostFocusListView (null, null);
-						return true;
-					}
-					RowActivated (null, null);
-					return true;
-				}
-				break;
-			case 1: //SHIFT
-				switch ((char)e.Key) {
-				case 'P':
-				case 'N':
-					KeyPressEventArgs fake_args = new KeyPressEventArgs ();
-					fake_args.Args = new object[] { e };
-					ListKeypressEvent (null, fake_args);
-					return true;
-				}
-				break;
-			}
-			return base.OnKeyPressEvent (e);
-		}
-		
-		void ListKeypressEvent (object sender, KeyPressEventArgs ex)
-		{
-			Gdk.Key key = ex.Event.Key;
-			char val = (char) key;
-			
-			switch (key) {
-				case Gdk.Key.Shift_L:
-				case Gdk.Key.Shift_R:
-				case Gdk.Key.Control_L:
-				case Gdk.Key.Control_R:
-					ex.RetVal = true;
-					return;
-					
-				case Gdk.Key.Escape:
-					LostFocusListView (null, null);
-					ex.RetVal = true;
-					return;
-
-				default:
-					if (val != '_' && !Char.IsLetterOrDigit (val)) {
-						TreeModel mdl;
-						TreeIter itr;
-						if (listView.Selection.GetSelected (out mdl, out itr)) {
-							ActivateItem (null, null);
-						} else {
-							LostFocusListView (null, null);
-						}
-						
-						ex.RetVal = true;
-						return;
-					} else {
-						control.Buffer.InsertAtCursor (val.ToString ());
-					}
-					break;
-			}
-
-			num_in++;
-
-			ShuffleSelection (false);
-	
-			ex.RetVal = true;
-		}
-
-		bool ShuffleSelection (bool magic)
-		{
-			// select the current typed word
-			int lastSelected = -1;
-			int capitalizationIndex = -1;
-			int numOfHits = 0;
-			
-			string typedString = GetTypedString ();
-			TreeIter iter;
-			int i = 0;
-			store.GetIterFirst (out iter);
-			do {
-				string text = (string) store.GetValue (iter, 0);
-				
-				if (text.ToUpper ().StartsWith (typedString.ToUpper ())) {
-					int currentCapitalizationIndex = 0;
-					for (int j = 0; j < typedString.Length && j < text.Length; ++j) {
-						if (typedString[j] == text[j]) {
-							++currentCapitalizationIndex;
-						}
-					}
-					if (currentCapitalizationIndex >= capitalizationIndex) {
-						numOfHits++;
-					}
-					
-					if (currentCapitalizationIndex > capitalizationIndex) {
-						lastSelected = i;
-						capitalizationIndex = currentCapitalizationIndex;
-					}
-				}
-				i++;
-			} while (store.IterNext (ref iter) == true);
-
-			if (lastSelected != -1) {
-				listView.Selection.UnselectAll ();
-				TreePath path = new TreePath (lastSelected.ToString ());
-				listView.SetCursor (path, complete_column, false);
-				listView.ScrollToCell (path, null, false, 0, 0);
-				if (magic && numOfHits == 1) {
-					ActivateItem (null, null);
-					LostFocusListView (null, null);
-					return true;
-				}
-			}
-			if (numOfHits == 0) {
-				control.buf.DropCompleteAhead ();
-				listView.Selection.UnselectAll ();
-			}
-			return false;
-		}
-		
-		void InitializeControls ()
-		{
-			Decorated = false;
-			SkipPagerHint = true;
-			SkipTaskbarHint = true;
-			TypeHint = Gdk.WindowTypeHint.Dialog;
-
-			TransientFor = (Gtk.Window)WorkbenchSingleton.Workbench;
-			
-			store = new Gtk.ListStore (typeof (string), typeof (Gdk.Pixbuf), typeof(ICompletionData));
-			listView = new Gtk.TreeView (store);
-			listView.HeadersVisible = false;
-
-			complete_column = new TreeViewColumn ();
-			complete_column.Title = "completion";
-
-			Gtk.CellRendererPixbuf pix_render = new Gtk.CellRendererPixbuf ();
-			complete_column.PackStart (pix_render, false);
-			complete_column.AddAttribute (pix_render, "pixbuf", 1);
-			
-			Gtk.CellRendererText text_render = new Gtk.CellRendererText ();
-			complete_column.PackStart (text_render, true);
-			complete_column.AddAttribute (text_render, "text", 0);
-	
-			listView.AppendColumn (complete_column);
-
-			Gtk.ScrolledWindow scroller = new Gtk.ScrolledWindow ();
-			scroller.HscrollbarPolicy = Gtk.PolicyType.Never;
-			scroller.Add (listView);
-
-			Gtk.Frame frame = new Gtk.Frame ();
-			frame.Add (scroller);
-			this.Add (frame);
-			
-			listView.KeyPressEvent += new KeyPressEventHandler (ListKeypressEvent);
-			this.FocusOutEvent += new FocusOutEventHandler (LostFocusListView);
-			this.AddEvents ((int) (Gdk.EventMask.LeaveNotifyMask));
-			listView.RowActivated += new RowActivatedHandler (ActivateItem);
-			listView.AddEvents ((int) (Gdk.EventMask.KeyPressMask));
-		}
-	
-		/// <remarks>
-		/// Shows the filled completion window, if it has no items it isn't shown.
-		/// </remarks>
-		public static void ShowWindow (char firstChar, TextIter trigIter, bool magic, ICompletionDataProvider provider, SourceEditorView ctrl)
-		{
-			wnd.ShowCompletionWindow (firstChar, trigIter, magic, provider, ctrl);
-		}
-
-		void ShowCompletionWindow (char firstChar, TextIter trigIter, bool magic, ICompletionDataProvider provider, SourceEditorView ctrl)
-		{
-			this.completionDataProvider = provider;
-			this.control = ctrl;
-			this.fileName = ctrl.ParentEditor.DisplayBinding.ContentName;
-			this.project = ctrl.ParentEditor.DisplayBinding.Project;
-			this.store.Clear ();
-			control.buf.StartAtomicUndo ();
-			triggeringMark = control.Buffer.CreateMark (null, trigIter, true);
-			origOffset = trigIter.Offset;
-			FillList (true, firstChar);
-
-			TreeIter iter;
-			if (store.GetIterFirst (out iter) == false) {
-				listView.FocusOutEvent -= new FocusOutEventHandler (LostFocusListView);
-				control.buf.EndAtomicUndo ();
-				control.GrabFocus ();
-				return;
-			}
-
-			listView.Selection.Changed -= new EventHandler (RowActivated);
-			if (magic) {
-				if (ShuffleSelection (true))
-					return;
-			}
-
-			Gdk.Rectangle rect = control.GetIterLocation (control.Buffer.GetIterAtMark (triggeringMark));
-
-			int wx, wy;
-			control.BufferToWindowCoords (Gtk.TextWindowType.Widget, rect.X /*+ rect.Width*/, rect.Y + rect.Height, out wx, out wy);
-			
-			int tx, ty;
-			control.GdkWindow.GetOrigin (out tx, out ty);
-			
-			ShowAll ();
-			Move (tx + wx, ty + wy);
-			Present ();
-			listView.GrabFocus ();
-			listView.Selection.Changed += new EventHandler (RowActivated);
-			RowActivated (null, null);
-		}
-		
-		/// <remarks>
-		/// Creates a new Completion window and puts it location under the caret
-		/// </remarks>
-		CompletionWindow () : base (Gtk.WindowType.Toplevel)
-		{
-			InitializeControls ();
-		}
-		
-		void ActivateItem (object sender, RowActivatedArgs e)
-		{
-			TreeModel foo;
-			TreeIter iter;
-			if (listView.Selection.GetSelected (out foo, out iter)) {
-				ICompletionData data = (ICompletionData) store.GetValue (iter, 2);
-				control.buf.DropCompleteAhead ();
-				DeleteInsertion ();
-				data.InsertAction (control);
-				LostFocusListView (null, null);
-			}
-		}
-		
-		void LostFocusListView (object sender, FocusOutEventArgs e)
-		{
-			control.buf.DropCompleteAhead ();
-			control.buf.EndAtomicUndo ();
-			listView.FocusOutEvent -= new FocusOutEventHandler (LostFocusListView);
-			control.HasFocus = true;
-			declarationviewwindow.HideAll ();
-			this.Hide ();
-		}
-		
-		void FillList (bool firstTime, char ch)
-		{
-			ICompletionData[] completionData = completionDataProvider.GenerateCompletionData(project, fileName, control, ch, triggeringMark);
-			if (completionData == null || completionData.Length == 0) {
-				return;
-			}
-			
-			foreach (ICompletionData data in completionData) {
-				store.AppendValues (data.Text[0], RenderIcon (data.Image, Gtk.IconSize.Menu, ""), data);
-			}
-			// sort here
-			store.SetSortColumnId (0, SortType.Ascending);
-		}
-		
-		void RowActivated (object sender, EventArgs a)
-		{
-			Gtk.TreeIter iter;
-			Gtk.TreeModel model;
-			
-			if (listView.Selection.GetSelected (out model, out iter)){
-				ICompletionData data = (ICompletionData) store.GetValue (iter, 2);
-				if (data == null)
-					return;
-				
-				int inst = insertLength;
-				if (inst == -1) {
-					LostFocusListView (null, null);
-					return;
-				}
-				if (inst >= 1) {
-					DeleteInsertion ();
-					int l = inst > data.CompletionString.Length ? data.CompletionString.Length : inst;
-					control.buf.InsertAtCursor (data.CompletionString.Substring (0, l));
-				}
-				control.buf.DropCompleteAhead ();
-				if (data.CompletionString.Length > inst) {
-					control.buf.DropCompleteAhead ();
-					control.buf.CompleteAhead (data.CompletionString.Substring(inst));
-				}
-				// This code is for sizing the treeview properly.
-				Gtk.TreePath path = store.GetPath (iter);
-				Gdk.Rectangle backRect = listView.GetBackgroundArea (path, (Gtk.TreeViewColumn)listView.Columns[0]);
-				
-				listView.HeightRequest = (backRect.Height * 5) + 2;
-
-				// FIXME: This code is buggy, and generates a bad placement sometimes when you jump a lot.
-				// but it is better than 0,0
-				// This code is for sizing the treeview properly.
-				
-				Gdk.Rectangle rect = listView.GetCellArea (path, (Gtk.TreeViewColumn)listView.Columns[0]);
-				int listpos_x = 0, listpos_y = 0;
-				while (listpos_x == 0)
-					GetPosition (out listpos_x, out listpos_y);
-				int vert = listpos_y + rect.Y;
-				
-				int lvWidth, lvHeight;
-				listView.GdkWindow.GetSize (out lvWidth, out lvHeight);
-				if (vert >= listpos_y + lvHeight - 2) {
-					vert = listpos_y + lvHeight - rect.Height;
-				} else if (vert < listpos_y) {
-					vert = listpos_y;
-				}
-				// FIXME: This is a bad calc, its always on the right,
-				// it needs to test if thats too big, and if so, place on the left;
-				int horiz = listpos_x + lvWidth + 30;
-				ICompletionDataWithMarkup wMarkup = data as ICompletionDataWithMarkup;
-				declarationviewwindow.Destroy ();
-				
-				if (wMarkup != null) {
-					declarationviewwindow = new DeclarationViewWindow ();
-					declarationviewwindow.DescriptionMarkup = wMarkup.DescriptionPango;
-				} else {
-					declarationviewwindow = new DeclarationViewWindow ();
-					declarationviewwindow.DescriptionMarkup = data.Description;
-				}
-			
-				if (declarationviewwindow.DescriptionMarkup.Length == 0)
-					return;
-	
-				declarationviewwindow.ShowAll ();
-
-				int dvwWidth, dvwHeight;
-	
-				declarationviewwindow.GdkWindow.GetSize (out dvwWidth, out dvwHeight);
-				if (listView.Screen.Width <= horiz + dvwWidth) {
-					horiz = listpos_x - dvwWidth - 10;
-				}
-			
-				declarationviewwindow.Move (horiz, vert);
-			}
-		}
-	}
-}
Index: Core/src/AddIns/DisplayBindings/SourceEditor/CodeCompletion/CommentCompletionDataProvider.cs
===================================================================
--- Core/src/AddIns/DisplayBindings/SourceEditor/CodeCompletion/CommentCompletionDataProvider.cs	(revision 2671)
+++ Core/src/AddIns/DisplayBindings/SourceEditor/CodeCompletion/CommentCompletionDataProvider.cs	(working copy)
@@ -13,6 +13,7 @@
 using MonoDevelop.Core.Properties;
 using MonoDevelop.Core.Services;
 using MonoDevelop.Gui;
+using MonoDevelop.Gui.Completion;
 using MonoDevelop.Internal.Templates;
 using MonoDevelop.Services;
 
@@ -63,7 +64,7 @@
 			return row >= region.BeginLine && (row <= region.EndLine || region.EndLine == -1);
 		}
 		
-		public ICompletionData[] GenerateCompletionData (Project project, string fileName, SourceEditorView textArea, char charTyped, Gtk.TextMark triggerMark)
+		public ICompletionData[] GenerateCompletionData (Project project, string fileName, ICompletionWidget widget, char charTyped)
 		{
 			/*caretLineNumber = textArea.Caret.Line;
 			caretColumn     = textArea.Caret.Column;
@@ -114,7 +115,7 @@
 				}
 			}
 			
-			public void InsertAction (SourceEditorView control)
+			public void InsertAction (ICompletionWidget widget)
 			{
 				//((SharpDevelopTextAreaControl)control).ActiveTextAreaControl.TextArea.InsertString(text);
 			}
Index: Core/src/AddIns/DisplayBindings/SourceEditor/CodeCompletion/ICompletionDataProvider.cs
===================================================================
--- Core/src/AddIns/DisplayBindings/SourceEditor/CodeCompletion/ICompletionDataProvider.cs	(revision 2671)
+++ Core/src/AddIns/DisplayBindings/SourceEditor/CodeCompletion/ICompletionDataProvider.cs	(working copy)
@@ -10,6 +10,7 @@
 using System.Reflection;
 using System.Collections;
 using MonoDevelop.Internal.Project;
+using MonoDevelop.Gui.Completion;
 
 using Gdk;
 
@@ -17,6 +18,6 @@
 
 namespace MonoDevelop.SourceEditor.CodeCompletion {
 	public interface ICompletionDataProvider {
-		ICompletionData[] GenerateCompletionData(Project project, string fileName, SourceEditorView textArea, char charTyped, Gtk.TextMark mark);
+		ICompletionData[] GenerateCompletionData(Project project, string fileName, ICompletionWidget widget, char charTyped);
 	}
 }
Index: Core/src/AddIns/DisplayBindings/SourceEditor/CodeCompletion/CodeCompletionDataProvider.cs
===================================================================
--- Core/src/AddIns/DisplayBindings/SourceEditor/CodeCompletion/CodeCompletionDataProvider.cs	(revision 2671)
+++ Core/src/AddIns/DisplayBindings/SourceEditor/CodeCompletion/CodeCompletionDataProvider.cs	(working copy)
@@ -16,6 +16,7 @@
 using MonoDevelop.Core.Properties;
 using MonoDevelop.Core.Services;
 using MonoDevelop.Gui;
+using MonoDevelop.Gui.Completion;
 using MonoDevelop.Internal.Templates;
 using MonoDevelop.Services;
 using MonoDevelop.Internal.Parser;
@@ -55,29 +56,26 @@
 		
 		ArrayList completionData = null;
 		
-		public ICompletionData[] GenerateCompletionData(Project project, string fileName, SourceEditorView textArea, char charTyped, TextMark triggerMark)
+		public ICompletionData[] GenerateCompletionData(Project project, string fileName, ICompletionWidget widget, char charTyped)
 		{
 			completionData = new ArrayList();
 			this.fileName = fileName;
 			
-			Gtk.TextIter insertIter = textArea.Buffer.GetIterAtMark (triggerMark);
-			
 			// the parser works with 1 based coordinates
-			
-			caretLineNumber      = insertIter.Line + 1;
-			caretColumn          = insertIter.LineOffset + 1;
+			caretLineNumber      = widget.TriggerLine + 1;
+			caretColumn          = widget.TriggerLineOffset + 1;
 			//string expression    = TextUtilities.GetExpressionBeforeOffset (textArea, insertIter.Offset);
 			ResolveResult results;
 			
 			IParserService parserService = (IParserService)MonoDevelop.Core.Services.ServiceManager.GetService(typeof(IParserService));
 			IExpressionFinder expressionFinder = parserService.GetExpressionFinder(fileName);
-			string expression    = expressionFinder == null ? TextUtilities.GetExpressionBeforeOffset(textArea, insertIter.Offset) : expressionFinder.FindExpression(textArea.Buffer.GetText(textArea.Buffer.StartIter, insertIter, true), insertIter.Offset - 2);
+			string expression    = expressionFinder == null ? TextUtilities.GetExpressionBeforeOffset(widget, widget.TriggerOffset) : expressionFinder.FindExpression(widget.GetText (0, widget.TriggerOffset), widget.TriggerOffset - 2);
 			if (expression == null) return null;
 			Console.WriteLine ("Expr: |{0}|", expression);
 			//FIXME: This chartyped check is a fucking *HACK*
 			if (expression == "is" || expression == "as") {
-				string expr = expressionFinder == null ? TextUtilities.GetExpressionBeforeOffset (textArea, insertIter.Offset - 3) : expressionFinder.FindExpression (textArea.Buffer.GetText (textArea.Buffer.StartIter, insertIter, true), insertIter.Offset - 5);
-				AddResolveResults (parserService.IsAsResolve (project, expr, caretLineNumber, caretColumn, fileName, textArea.Buffer.Text));
+				string expr = expressionFinder == null ? TextUtilities.GetExpressionBeforeOffset (widget, widget.TriggerOffset - 3) : expressionFinder.FindExpression (widget.GetText (0, widget.TriggerOffset), widget.TriggerOffset - 5);
+				AddResolveResults (parserService.IsAsResolve (project, expr, caretLineNumber, caretColumn, fileName, widget.GetText (0, widget.TextLength)));
 				return (ICompletionData[])completionData.ToArray (typeof (ICompletionData));
 			}
 			if (ctrlspace && charTyped != '.') {
@@ -92,7 +90,7 @@
 			} else {
 				//FIXME: I added the null check, #D doesnt need it, why do we?
 				if (fileName != null) {
-					results = parserService.Resolve(project, expression, caretLineNumber, caretColumn, fileName, textArea.Buffer.Text);
+					results = parserService.Resolve(project, expression, caretLineNumber, caretColumn, fileName, widget.GetText (0, widget.TextLength));
 					AddResolveResults(results);
 				}
 			}
Index: Core/src/AddIns/DisplayBindings/SourceEditor/CodeCompletion/TemplateCompletionDataProvider.cs
===================================================================
--- Core/src/AddIns/DisplayBindings/SourceEditor/CodeCompletion/TemplateCompletionDataProvider.cs	(revision 2671)
+++ Core/src/AddIns/DisplayBindings/SourceEditor/CodeCompletion/TemplateCompletionDataProvider.cs	(working copy)
@@ -15,6 +15,7 @@
 using MonoDevelop.Internal.Project;
 using MonoDevelop.SourceEditor.Gui;
 using Stock = MonoDevelop.Gui.Stock;
+using MonoDevelop.Gui.Completion;
 
 namespace MonoDevelop.SourceEditor.CodeCompletion
 {
@@ -27,7 +28,7 @@
 			}
 		}
 		
-		public ICompletionData[] GenerateCompletionData(Project project, string fileName, SourceEditorView textArea, char charTyped, Gtk.TextMark triggerMark)
+		public ICompletionData[] GenerateCompletionData(Project project, string fileName, ICompletionWidget widget, char charTyped)
 		{
 			CodeTemplateGroup templateGroup = CodeTemplateLoader.GetTemplateGroupPerFilename(fileName);
 			if (templateGroup == null) {
@@ -74,7 +75,7 @@
 				}
 			}
 			
-			public void InsertAction(SourceEditorView control)
+			public void InsertAction(ICompletionWidget widget)
 			{
 				//((SharpDevelopTextAreaControl)control).InsertTemplate(template);
 			}
Index: Core/src/AddIns/DisplayBindings/SourceEditor/Makefile.am
===================================================================
--- Core/src/AddIns/DisplayBindings/SourceEditor/Makefile.am	(revision 2671)
+++ Core/src/AddIns/DisplayBindings/SourceEditor/Makefile.am	(working copy)
@@ -5,7 +5,6 @@
 FILES = \
 CodeCompletion/CodeCompletionData.cs \
 CodeCompletion/ICompletionData.cs \
-CodeCompletion/CompletionWindow.cs \
 CodeCompletion/CompletionListWindow.cs \
 CodeCompletion/ListWindow.cs \
 CodeCompletion/TextUtilities.cs \
-------------- next part --------------
Index: Extras/BooBinding/Gui/IShellModel.boo
===================================================================
--- Extras/BooBinding/Gui/IShellModel.boo	(revision 2671)
+++ Extras/BooBinding/Gui/IShellModel.boo	(working copy)
@@ -20,6 +20,7 @@
 namespace BooBinding.Gui
 
 import System
+import System.Collections
 import BooBinding.Properties
 
 interface IShellModel:
@@ -45,9 +46,16 @@
 		pass
 
 	Properties as ShellProperties:
-		get:
-			pass
+		get
 
+	LanguageName as string:
+		get
+
 	MimeType as string:
-		get:
-			pass
+		get
+	
+	MimeTypeExtension as string:
+		get
+	
+	References as IList:
+		get
Index: Extras/BooBinding/Gui/ShellTextView.boo
===================================================================
--- Extras/BooBinding/Gui/ShellTextView.boo	(revision 2671)
+++ Extras/BooBinding/Gui/ShellTextView.boo	(working copy)
@@ -31,11 +31,13 @@
 import GtkSourceView
 
 import MonoDevelop.Gui.Widgets
+import MonoDevelop.Gui.Completion
 import MonoDevelop.Core.Services
 import MonoDevelop.Services
 import MonoDevelop.Core.Properties
 import MonoDevelop.Internal.Project
 
+import MonoDevelop.SourceEditor.CodeCompletion
 
 /*
  * TODO
@@ -44,9 +46,10 @@
  * 2) Don't record lines with errors in the _scriptLines buffer
  */
 
-class ShellTextView (SourceView):
+class ShellTextView (SourceView, ICompletionWidget):
 	private static _promptRegular = ">>> "
 	private static _promptMultiline = "... "
+	private static _fakeFileName as string
 	
 	[Getter(Model)]
 	model as IShellModel
@@ -68,9 +71,14 @@
 	private _proj as Project
 
 	private _assembliesLoaded as bool
+
+	private _fakeProject as DotNetProject
+	private _parserService as DefaultParserService
+	private _fileInfo as FileStream
 	
 	def constructor(model as IShellModel):
 		service = cast(SourceViewService,ServiceManager.GetService(typeof(SourceViewService)))
+		_parserService = cast(IParserService, ServiceManager.GetService (typeof (DefaultParserService)))
 		buf = SourceBuffer(service.GetLanguageFromMimeType(model.MimeType))
 
 		// This freaks out booc for some reason.
@@ -82,6 +90,14 @@
 		self.WrapMode = Gtk.WrapMode.Word
 		self.ModifyFont(Model.Properties.Font)
 
+		_fakeFileName = "/tmp/shell-dummy-file.${Model.MimeTypeExtension}"
+		_fileInfo  = System.IO.File.Create (_fakeFileName)
+
+		# FIXME: Put the project file somewhere other than /tmp
+		_fakeProject = DotNetProject(Model.LanguageName, Name: "___ShellProject", FileName: "/tmp/shell-project.mdp")
+
+		_parserService.LoadProjectDatabase(_fakeProject)
+
 		Model.Properties.InternalProperties.PropertyChanged += OnPropertyChanged
 		Model.RegisterOutputHandler (HandleOutput)
 
@@ -155,6 +171,10 @@
 			for line as string in output:
 				processOutput (line )
 		prompt (true)
+		for assembly in Model.References:
+			_fakeProject.AddReference(assembly)
+
+		GLib.Idle.Add( { _parserService.ParseFile (_fakeFileName, _scriptLines) } )
 		return false
 			
 	override def Dispose():
@@ -208,6 +228,9 @@
 		_reset.Show()
 	
 	override def OnKeyPressEvent (ev as Gdk.EventKey):
+		if CompletionListWindow.ProcessKeyEvent (ev):
+			return true
+		
 		// Short circuit to avoid getting moved back to the input line
 		// when paging up and down in the shell output
 		if ev.Key in Gdk.Key.Page_Up, Gdk.Key.Page_Down:
@@ -219,6 +242,9 @@
 			Buffer.MoveMark (Buffer.SelectionBound, InputLineEnd)
 			Buffer.MoveMark (Buffer.InsertMark, InputLineEnd)
 		
+		if (ev.State == Gdk.ModifierType.ControlMask) and ev.Key == Gdk.Key.space:
+			TriggerCodeCompletion ()
+
 		if ev.Key == Gdk.Key.Return:
 			if _inBlock:
 				if InputLine == "":
@@ -237,7 +263,7 @@
 			else:
 				// Special case for start of new code block
 				if InputLine.Trim()[-1:] == ":":
-					_inBlock = true;
+					_inBlock = true
 					_blockText = InputLine
 					prompt (true, true)
 					if _auto_indent:
@@ -268,7 +294,7 @@
 		elif ev.Key == Gdk.Key.Up:
 			if (not _inBlock) and _commandHistoryPast.Count > 0:
 				if _commandHistoryFuture.Count == 0:
-					_commandHistoryFuture.Push(InputLine);
+					_commandHistoryFuture.Push(InputLine)
 				else:
 					if _commandHistoryPast.Count == 1:
 						return true
@@ -297,6 +323,12 @@
 				Buffer.MoveMark (Buffer.SelectionBound, InputLineBegin)
 			return true
 
+		elif ev.Key == Gdk.Key.period:
+			ret = super.OnKeyPressEvent(ev)
+			prepareCompletionDetails (Buffer.GetIterAtMark (Buffer.InsertMark))
+			CompletionListWindow.ShowWindow(char('.'), CodeCompletionDataProvider (true), self, _fakeProject, _fakeFileName)
+			return ret
+
 		// Short circuit to avoid getting moved back to the input line
 		// when paging up and down in the shell output
 		elif ev.Key in Gdk.Key.Page_Up, Gdk.Key.Page_Down:
@@ -304,8 +336,41 @@
 		
 		return super (ev)
 	
+	protected override def OnFocusOutEvent (e as EventFocus):
+		CompletionListWindow.HideWindow ()
+		return super.OnFocusOutEvent(e)
+	
 	#endregion
 
+	private def TriggerCodeCompletion():
+		iter = Cursor
+		triggerChar = char('\0')
+		triggerIter = TextIter.Zero
+		if (iter.Char != null and  iter.Char.Length > 0):
+			if iter.Char[0] in (char(' '), char('\t'), char('.'), char('('), char('[')):
+				triggerIter = iter
+				triggerChar = iter.Char[0]
+
+		while iter.LineOffset > 0 and triggerIter.Equals (TextIter.Zero):
+			if (iter.Char == null or iter.Char.Length == 0):
+				iter.BackwardChar ()
+				continue
+
+			if iter.Char[0] in (char(' '), char('\t'), char('.'), char('('), char('[')):
+				triggerIter = iter
+				triggerChar = iter.Char[0]
+				break
+
+			iter.BackwardChar ()
+		
+		if (triggerIter.Equals (TextIter.Zero)):
+			return
+
+		triggerIter.ForwardChar ()
+		
+		prepareCompletionDetails (triggerIter)
+		CompletionListWindow.ShowWindow (triggerChar, CodeCompletionDataProvider (true), self, _fakeProject, _fakeFileName)
+
 	// Mark to find the beginning of our next input line
 	private _endOfLastProcessing as TextMark
 
@@ -403,3 +468,76 @@
 		return
 
 	#endregion
+
+	private def prepareCompletionDetails (triggerIter as TextIter):
+		rect = GetIterLocation (Buffer.GetIterAtMark (Buffer.InsertMark))
+
+		wx as int
+		wy as int
+		BufferToWindowCoords (Gtk.TextWindowType.Widget, rect.X, rect.Y + rect.Height, wx, wy)
+
+		tx as int
+		ty as int
+		GdkWindow.GetOrigin (tx, ty)
+
+		self.completionX = tx + wx
+		self.completionY = ty + wy
+		self.textHeight = rect.Height
+		self.triggerMark = Buffer.CreateMark (null, triggerIter, true)
+
+	#region ICompletionWidget
+
+	[Getter(ICompletionWidget.TriggerXCoord)]
+	private completionX
+
+	[Getter(ICompletionWidget.TriggerYCoord)]
+	private completionY
+	
+	[Getter(ICompletionWidget.TriggerTextHeight)]
+	private textHeight as int
+	
+	ICompletionWidget.Text:
+		get:
+			return Buffer.Text
+	
+	ICompletionWidget.TextLength:
+		get:
+			return Buffer.EndIter.Offset
+	
+	def ICompletionWidget.GetChar (offset as int) as System.Char:
+		return Buffer.GetIterAtLine (offset).Char[0]
+	
+	def ICompletionWidget.GetText (startOffset as int, endOffset as int) as string:
+		return Buffer.GetText(Buffer.GetIterAtOffset (startOffset), Buffer.GetIterAtOffset(endOffset), true)
+	
+	ICompletionWidget.CompletionText:
+		get:
+			return Buffer.GetText (Buffer.GetIterAtMark (triggerMark), Buffer.GetIterAtMark (Buffer.InsertMark), false)
+	
+	def ICompletionWidget.SetCompletionText (partial_word as string, complete_word as string):
+		offsetIter = Buffer.GetIterAtMark(triggerMark)
+		endIter = Buffer.GetIterAtOffset (offsetIter.Offset + partial_word.Length)
+		Buffer.MoveMark (Buffer.InsertMark, offsetIter)
+		Buffer.Delete (offsetIter, endIter)
+		Buffer.InsertAtCursor (complete_word)
+	
+	def ICompletionWidget.InsertAtCursor (text as string):
+		Buffer.InsertAtCursor (text)
+	
+	private triggerMark as TextMark
+	ICompletionWidget.TriggerOffset:
+		get:
+			return Buffer.GetIterAtMark (triggerMark).Offset
+
+	ICompletionWidget.TriggerLine:
+		get:
+			return Buffer.GetIterAtMark (triggerMark).Line
+
+	ICompletionWidget.TriggerLineOffset:
+		get:
+			return Buffer.GetIterAtMark (triggerMark).LineOffset
+	
+	ICompletionWidget.GtkStyle:
+		get:
+			return self.Style.Copy();
+	#endregion
Index: Extras/BooBinding/Gui/BooShellModel.boo
===================================================================
--- Extras/BooBinding/Gui/BooShellModel.boo	(revision 2671)
+++ Extras/BooBinding/Gui/BooShellModel.boo	(working copy)
@@ -49,24 +49,32 @@
 		get:
 			return "text/x-boo"
 
+	LanguageName as string:
+		get:
+			return "Boo"
+
+	MimeTypeExtension as string:
+		get:
+			return "boo"
+	
 	Properties as ShellProperties:
 		get:
 			return _props
 	
-	def constructor ():
-		pass
-
-	def constructor (program_path as string, socket_path as string):
-		GetRemoteShellObject ()
+	References as IList:
+		get:	
+			return _booShell.References
+	
+	def constructor():
+		getRemoteShellObject()
 		_booShell.Run ()
 
-	def GetRemoteShellObject ():
+	private def getRemoteShellObject ():
 		_procService as ProcessService = ServiceManager.GetService (typeof (ProcessService))
 		_booShell = _procService.CreateExternalProcessObject ("../AddIns/BackendBindings/BooShell.dll", "BooBinding.BooShell.BooShell", false)
 		if _booShell is null:
 			raise Exception ("Unable to instantiate remote BooShell object")
-
-			
+	
 	def Reset () as bool:
 		_booShell.Reset()
 		return true
Index: Extras/BooBinding/Gui/OptionPanels/CodeCompilationPanel.boo
===================================================================
--- Extras/BooBinding/Gui/OptionPanels/CodeCompilationPanel.boo	(revision 2671)
+++ Extras/BooBinding/Gui/OptionPanels/CodeCompilationPanel.boo	(working copy)
@@ -105,9 +105,7 @@
 		labelCompileTarget.Markup = String.Format ("{0} :", GettextCatalog.GetString ("Output Assembly"))
 		
 
-		typeArray = array(System.Type, 1)
-		typeArray[0] = typeof(string)
-		store = ListStore (typeArray)
+		store = ListStore ((typeof(string),))
 
 		stringArray = array(System.String, 1)
 		stringArray[0] = GettextCatalog.GetString ("Executable")
Index: Extras/BooBinding/Properties/ShellProperties.boo
===================================================================
--- Extras/BooBinding/Properties/ShellProperties.boo	(revision 2671)
+++ Extras/BooBinding/Properties/ShellProperties.boo	(working copy)
@@ -17,7 +17,7 @@
 	private propertyService = cast (PropertyService, ServiceManager.GetService (typeof(PropertyService)))
 	private properties = cast (IProperties, propertyService.GetProperty (PropertyName, DefaultProperties()))
 
-	public virtual PropertyName as string:
+	public abstract PropertyName as string:
 		get:
 			pass
 
Index: Extras/BooBinding/Parser/BooParser.boo
===================================================================
--- Extras/BooBinding/Parser/BooParser.boo	(revision 2671)
+++ Extras/BooBinding/Parser/BooParser.boo	(working copy)
@@ -67,8 +67,8 @@
 	def Parse(fileName as string, fileContent as string) as ICompilationUnitBase:
 		//print "Parse ${fileName} with content"
 		
-		cr = '\r'[0]
-		ln = '\n'[0]
+		cr = char('\r')
+		ln = char('\n')
 		linecount = 1
 		for c as Char in fileContent:
 			linecount += 1 if c == ln
@@ -87,15 +87,20 @@
 		compiler = BooCompiler()
 		compiler.Parameters.Input.Add(StringInput(fileName, fileContent))
 		project as Project
-		for entry as Project in MonoDevelop.Services.Runtime.ProjectService.CurrentOpenCombine.GetAllProjects():
-			if entry.IsFileInProject(fileName):
-				project = entry
-				
-		return Parse(fileName, lineLength, compiler, project)
+		if MonoDevelop.Services.Runtime.ProjectService.CurrentOpenCombine is not null:
+			for entry as Project in MonoDevelop.Services.Runtime.ProjectService.CurrentOpenCombine.GetAllProjects():
+				if entry.IsFileInProject(fileName):
+					project = entry
+		
+		if project is not null and project.ProjectReferences is not null:
+			for projectRef as ProjectReference in project.ProjectReferences:
+				compiler.Parameters.References.Add(System.Reflection.Assembly.LoadFile(projectRef.GetReferencedFileName()))
+		
+		return Parse(fileName, lineLength, compiler)
 	
-	private def Parse(fileName as string, lineLength as (int), compiler as BooCompiler, project as Project):
+	private def Parse(fileName as string, lineLength as (int), compiler as BooCompiler):
 		compiler.Parameters.OutputWriter = StringWriter()
-		compiler.Parameters.TraceSwitch.Level = TraceLevel.Warning;
+		compiler.Parameters.TraceSwitch.Level = TraceLevel.Warning
 		
 		compilePipe = Compile()
 		parsingStep as Boo.Lang.Parser.BooParsingStep = compilePipe[0]
@@ -117,8 +122,6 @@
 		
 		compilePipe.BreakOnErrors = false
 		compiler.Parameters.Pipeline = compilePipe
-		for projectRef as ProjectReference in project.ProjectReferences:
-			compiler.Parameters.References.Add(System.Reflection.Assembly.LoadFile(projectRef.GetReferencedFileName()))
 		
 		try:
 			compiler.Run()
Index: Extras/BooBinding/BooShellPadContent.boo
===================================================================
--- Extras/BooBinding/BooShellPadContent.boo	(revision 2671)
+++ Extras/BooBinding/BooShellPadContent.boo	(working copy)
@@ -35,23 +35,23 @@
 
 	override Control:
 		get:
+			if _scroller is null:
+				CreateBooShell()
 			return _scroller
 	
 	def constructor():
 		super( "Boo Shell", "md-boo-binding-base" )
-		CreateBooShell()
 	
 	def CreateBooShell():
 		_scroller = Gtk.ScrolledWindow()
-		_user = System.Environment.GetEnvironmentVariable("USER")
-		_model = BooShellModel ("../AddIns/BackendBindings/BooShellServer.exe", "/tmp/md-booshell-${_user}")
+		_model = BooShellModel ()
 		_shellView = ShellTextView (_model)
 		_scroller.Add(_shellView)
 		_scroller.ShowAll()
 
 	override def RedrawContent():
-		OnTitleChanged(null);
-		OnIconChanged(null);
+		OnTitleChanged(null)
+		OnIconChanged(null)
 
 	override def Dispose():
 		_shellView.Dispose()
Index: Extras/BooBinding/BooShell/BooShell.boo
===================================================================
--- Extras/BooBinding/BooShell/BooShell.boo	(revision 2671)
+++ Extras/BooBinding/BooShell/BooShell.boo	(working copy)
@@ -52,6 +52,19 @@
 		EnqueueCommand (ShellCommand (ShellCommandType.Load, assemblyPath))
 		return true
 	
+	References as IList:
+		get:
+			list = []
+			Monitor.Enter (_interpreter)
+			for assembly as System.Reflection.Assembly in _interpreter.References.List:
+				try:
+					loc = assembly.Location
+					list.Add (loc)
+				except x:
+					continue
+			Monitor.Exit (_interpreter)
+			return list
+	
 	def GetOutput() as (string):
 		ret as (string)
 		try:
@@ -78,7 +91,7 @@
 		GLib.Idle.Add(ProcessCommands)
 		Application.Run()
 
-	def ProcessCommands() as bool:
+	private def ProcessCommands() as bool:
 		com as ShellCommand
 		try:
 			Monitor.Enter (_commandQueue)
@@ -89,6 +102,7 @@
 
 			com = _commandQueue.Dequeue()
 
+			Monitor.Enter(_interpreter)
 			if com.Type == ShellCommandType.Eval:
 				if com.Data is not null:
 					_interpreter.LoopEval(com.Data)
@@ -97,7 +111,9 @@
 			elif com.Type == ShellCommandType.Load:
 				if com.Data is not null:
 					_interpreter.load(com.Data)
-	
+
+			Monitor.Exit(_interpreter)
+
 			com.Type = ShellCommandType.NoOp
 	
 			if _commandQueue.Count == 0:
@@ -115,15 +131,16 @@
 
 	
 	private def kickOffGuiThread():
-		_thread = System.Threading.Thread(ThreadRun)
-		_thread.Start()
+		_start as ThreadStart = ThreadRun
+		_thread = System.Threading.Thread (_start)
+		_thread.Start ()
 	
-	def print(obj):
+	private def print(obj):
 		Monitor.Enter (_outputQueue)
 		_outputQueue.Enqueue(obj)
 		Monitor.Exit (_outputQueue)
 	
-	def EnqueueCommand (command as ShellCommand):
+	private def EnqueueCommand (command as ShellCommand):
 		if not _thread.IsAlive:
 			kickOffGuiThread()
 


More information about the Monodevelop-list mailing list