// CSharp Editor Example with Code Completion
// Copyright (c) 2006, Daniel Grunwald
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// - Redistributions of source code must retain the above copyright notice, this list
// of conditions and the following disclaimer.
//
// - Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other materials
// provided with the distribution.
//
// - Neither the name of the ICSharpCode team nor the names of its contributors may be used to
// endorse or promote products derived from this software without specific prior written
// permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &AS IS& AND ANY EXPRESS
// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Windows.Forms;
using ICSharpCode.TextEditor;
using ICSharpCode.TextEditor.Gui.CompletionWindow;
using Dom = ICSharpCode.SharpDevelop.Dom;
using NRefactoryResolver = ICSharpCode.SharpDevelop.Dom.NRefactoryResolver.NRefactoryResolver;
namespace HeuristicLab.CodeEditor {
class CodeCompletionProvider : ICompletionDataProvider {
CodeEditor codeEditor;
public CodeCompletionProvider(CodeEditor codeEditor) {
this.codeEditor = codeEditor;
}
public ImageList ImageList {
get {
return codeEditor.imageList1;
}
}
public string PreSelection {
get {
return null;
}
}
public int DefaultIndex {
get {
return -1;
}
}
public CompletionDataProviderKeyResult ProcessKey(char key) {
if (char.IsLetterOrDigit(key) || key == '_') {
return CompletionDataProviderKeyResult.NormalKey;
} else {
// key triggers insertion of selected items
return CompletionDataProviderKeyResult.InsertionKey;
}
}
///
/// Called when entry should be inserted. Forward to the insertion action of the completion data.
///
public bool InsertAction(ICompletionData data, TextArea textArea, int insertionOffset, char key) {
textArea.Caret.Position = textArea.Document.OffsetToPosition(insertionOffset);
return data.InsertAction(textArea, key);
}
public ICompletionData[] GenerateCompletionData(string fileName, TextArea textArea, char charTyped) {
// We can return code-completion items like this:
//return new ICompletionData[] {
// new DefaultCompletionData("Text", "Description", 1)
//};
NRefactoryResolver resolver = new NRefactoryResolver(codeEditor.projectContent.Language);
Dom.ResolveResult rr = resolver.Resolve(FindExpression(textArea),
codeEditor.parseInformation,
textArea.MotherTextEditorControl.Text);
List resultList = new List();
if (rr != null) {
try {
ArrayList completionData = rr.GetCompletionData(codeEditor.projectContent);
if (completionData != null) {
AddCompletionData(resultList, completionData);
}
}
catch (NullReferenceException) { }
}
return resultList.ToArray();
}
///
/// Find the expression the cursor is at.
/// Also determines the context (using statement, "new"-expression etc.) the
/// cursor is at.
///
Dom.ExpressionResult FindExpression(TextArea textArea) {
Dom.IExpressionFinder finder;
finder = new Dom.CSharp.CSharpExpressionFinder(codeEditor.parseInformation);
Dom.ExpressionResult expression = finder.FindExpression(textArea.Document.TextContent, textArea.Caret.Offset);
if (expression.Region.IsEmpty) {
expression.Region = new Dom.DomRegion(textArea.Caret.Line + 1, textArea.Caret.Column + 1);
}
return expression;
}
void AddCompletionData(List resultList, ArrayList completionData) {
// used to store the method names for grouping overloads
Dictionary nameDictionary = new Dictionary();
// Add the completion data as returned by SharpDevelop.Dom to the
// list for the text editor
foreach (object obj in completionData) {
if (obj is string) {
// namespace names are returned as string
resultList.Add(new DefaultCompletionData((string)obj, "namespace " + obj, 5));
} else if (obj is Dom.IClass) {
Dom.IClass c = (Dom.IClass)obj;
resultList.Add(new CodeCompletionData(c));
} else if (obj is Dom.IMember) {
Dom.IMember m = (Dom.IMember)obj;
if (m is Dom.IMethod && ((m as Dom.IMethod).IsConstructor)) {
// Skip constructors
continue;
}
// Group results by name and add "(x Overloads)" to the
// description if there are multiple results with the same name.
CodeCompletionData data;
if (nameDictionary.TryGetValue(m.Name, out data)) {
data.AddOverload(m);
} else {
nameDictionary[m.Name] = data = new CodeCompletionData(m);
resultList.Add(data);
}
} else {
// Current ICSharpCode.SharpDevelop.Dom should never return anything else
throw new NotSupportedException();
}
}
}
}
}