// 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.Text;
using System.Windows.Forms;
using ICSharpCode.TextEditor;
using ICSharpCode.TextEditor.Gui.CompletionWindow;
using Dom = ICSharpCode.SharpDevelop.Dom;
using NRefactoryResolver = ICSharpCode.SharpDevelop.Dom.NRefactoryResolver.NRefactoryResolver;
using CSTextEditor;
namespace CodeComplete
{
class CodeCompletionProvider : ICompletionDataProvider
{
MainForm Form1;
public CodeCompletionProvider(MainForm Form1)
{
this.Form1 = Form1;
}
public ImageList ImageList {
get {
return Form1.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(Form1.myProjectContent, Form1.myProjectContent.Language);
Dom.ResolveResult rr = resolver.Resolve(FindExpression(textArea),
textArea.Caret.Line,
textArea.Caret.Column,
fileName,
textArea.MotherTextEditorControl.Text);
List resultList = new List();
if (rr != null) {
ArrayList completionData = rr.GetCompletionData(Form1.myProjectContent);
if (completionData != null) {
AddCompletionData(resultList, completionData);
}
}
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.CSharp.CSharpExpressionFinder finder;
finder = new Dom.CSharp.CSharpExpressionFinder(MainForm.CompilableFileName);
return finder.FindExpression(textArea.Document.TextContent, textArea.Caret.Offset);
}
void AddCompletionData(List resultList, ArrayList completionData)
{
// 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;
if (c.ClassType == Dom.ClassType.Enum) {
resultList.Add(new DefaultCompletionData(c.Name,
GetDescription(c),
4));
} else { // missing: struct, delegate etc.
resultList.Add(new DefaultCompletionData(c.Name,
GetDescription(c),
0));
}
} 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;
}
// TODO: Group results by name and add "(x Overloads)" to the
// description if there are multiple results with the same name.
resultList.Add(new DefaultCompletionData(m.Name,
GetDescription(m),
GetMemberImageIndex(m)));
} else {
// Current ICSharpCode.SharpDevelop.Dom should never return anything else
throw new NotSupportedException();
}
}
}
///
/// Converts a member to text.
/// Returns the declaration of the member as C# code, e.g.
/// "public void MemberName(string parameter)"
///
string GetDescription(Dom.IDecoration entity)
{
return GetCSharpText(entity) + Environment.NewLine + entity.Documentation;
}
string GetCSharpText(Dom.IDecoration entity)
{
if (entity is Dom.IMethod)
return Dom.CSharp.CSharpAmbience.Instance.Convert(entity as Dom.IMethod);
if (entity is Dom.IProperty)
return Dom.CSharp.CSharpAmbience.Instance.Convert(entity as Dom.IProperty);
if (entity is Dom.IEvent)
return Dom.CSharp.CSharpAmbience.Instance.Convert(entity as Dom.IEvent);
if (entity is Dom.IField)
return Dom.CSharp.CSharpAmbience.Instance.Convert(entity as Dom.IField);
if (entity is Dom.IClass)
return Dom.CSharp.CSharpAmbience.Instance.Convert(entity as Dom.IClass);
// unknown entity:
return entity.ToString();
}
int GetMemberImageIndex(Dom.IMember member)
{
// Missing: different icons for private/public member
if (member is Dom.IMethod)
return 1;
if (member is Dom.IProperty)
return 2;
if (member is Dom.IField)
return 3;
if (member is Dom.IEvent)
return 6;
return 3;
}
}
}