Browse Source

Improved CSharpCodeCompletion sample: add tool tip support, show only one entry for overloaded methods

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/branches/2.1@2673 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Daniel Grunwald 18 years ago
parent
commit
3acc3cbb3e
  1. 2
      samples/CSharpCodeCompletion/CSharpCodeCompletion.csproj
  2. 112
      samples/CSharpCodeCompletion/CodeCompletionData.cs
  3. 66
      samples/CSharpCodeCompletion/CodeCompletionProvider.cs
  4. 3
      samples/CSharpCodeCompletion/MainForm.cs
  5. 146
      samples/CSharpCodeCompletion/ToolTipProvider.cs

2
samples/CSharpCodeCompletion/CSharpCodeCompletion.csproj

@ -51,6 +51,7 @@ @@ -51,6 +51,7 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="CodeCompletionData.cs" />
<Compile Include="MainForm.cs" />
<Compile Include="MainForm.Designer.cs">
<DependentUpon>MainForm.cs</DependentUpon>
@ -62,6 +63,7 @@ @@ -62,6 +63,7 @@
<Compile Include="CodeCompletionProvider.cs" />
<Compile Include="CodeCompletionKeyHandler.cs" />
<Compile Include="HostCallbackImplementation.cs" />
<Compile Include="ToolTipProvider.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
</Project>

112
samples/CSharpCodeCompletion/CodeCompletionData.cs

@ -0,0 +1,112 @@ @@ -0,0 +1,112 @@
/*
* Erstellt mit SharpDevelop.
* Benutzer: grunwald
* Datum: 27.08.2007
* Zeit: 14:25
*
* Sie können diese Vorlage unter Extras > Optionen > Codeerstellung > Standardheader ändern.
*/
using System;
using ICSharpCode.TextEditor.Gui.CompletionWindow;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Dom.CSharp;
namespace CSharpEditor
{
/// <summary>
/// Represents an item in the code completion window.
/// </summary>
class CodeCompletionData : DefaultCompletionData, ICompletionData
{
IMember member;
IClass c;
public CodeCompletionData(IMember member)
: base(member.Name, null, GetMemberImageIndex(member))
{
this.member = member;
}
public CodeCompletionData(IClass c)
: base(c.Name, null, GetClassImageIndex(c))
{
this.c = c;
}
int overloads = 0;
public void AddOverload()
{
overloads++;
}
static int GetMemberImageIndex(IMember member)
{
// Missing: different icons for private/public member
if (member is IMethod)
return 1;
if (member is IProperty)
return 2;
if (member is IField)
return 3;
if (member is IEvent)
return 6;
return 3;
}
static int GetClassImageIndex(IClass c)
{
switch (c.ClassType) {
case ClassType.Enum:
return 4;
default:
return 0;
}
}
string description;
// DefaultCompletionData.Description is not virtual, but we can reimplement
// the interface to get the same effect as overriding.
string ICompletionData.Description {
get {
if (description == null) {
IDecoration entity = (IDecoration)member ?? c;
description = GetCSharpText(entity);
if (overloads > 1) {
description += " (+" + overloads + " overloads)";
}
description += Environment.NewLine + XmlDocumentationToText(entity.Documentation);
}
return description;
}
}
/// <summary>
/// Converts a member to text.
/// Returns the declaration of the member as C# code, e.g.
/// "public void MemberName(string parameter)"
/// </summary>
static string GetCSharpText(IDecoration entity)
{
if (entity is IMethod)
return CSharpAmbience.Instance.Convert(entity as IMethod);
if (entity is IProperty)
return CSharpAmbience.Instance.Convert(entity as IProperty);
if (entity is IEvent)
return CSharpAmbience.Instance.Convert(entity as IEvent);
if (entity is IField)
return CSharpAmbience.Instance.Convert(entity as IField);
if (entity is IClass)
return CSharpAmbience.Instance.Convert(entity as IClass);
// unknown entity:
return entity.ToString();
}
public static string XmlDocumentationToText(string xmlDoc)
{
return xmlDoc;
}
}
}

66
samples/CSharpCodeCompletion/CodeCompletionProvider.cs

@ -122,6 +122,9 @@ namespace CSharpEditor @@ -122,6 +122,9 @@ namespace CSharpEditor
void AddCompletionData(List<ICompletionData> resultList, ArrayList completionData)
{
// used to store method the names for grouping overloads
Dictionary<string, CodeCompletionData> nameDictionary = new Dictionary<string, CodeCompletionData>();
// Add the completion data as returned by SharpDevelop.Dom to the
// list for the text editor
foreach (object obj in completionData) {
@ -130,71 +133,28 @@ namespace CSharpEditor @@ -130,71 +133,28 @@ namespace CSharpEditor
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));
}
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;
}
// TODO: Group results by name and add "(x Overloads)" to the
// 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)));
CodeCompletionData data;
if (nameDictionary.TryGetValue(m.Name, out data)) {
data.AddOverload();
} else {
nameDictionary[m.Name] = data = new CodeCompletionData(m);
resultList.Add(data);
}
} else {
// Current ICSharpCode.SharpDevelop.Dom should never return anything else
throw new NotSupportedException();
}
}
}
/// <summary>
/// Converts a member to text.
/// Returns the declaration of the member as C# code, e.g.
/// "public void MemberName(string parameter)"
/// </summary>
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;
}
}
}

3
samples/CSharpCodeCompletion/MainForm.cs

@ -80,8 +80,9 @@ class MainClass @@ -80,8 +80,9 @@ class MainClass
";
textEditorControl1.SetHighlighting("C#");
textEditorControl1.ShowEOLMarkers = false;
CodeCompletionKeyHandler.Attach(this, textEditorControl1);
HostCallbackImplementation.Register(this);
CodeCompletionKeyHandler.Attach(this, textEditorControl1);
ToolTipProvider.Attach(this, textEditorControl1);
pcRegistry = new Dom.ProjectContentRegistry(); // Default .NET 2.0 registry

146
samples/CSharpCodeCompletion/ToolTipProvider.cs

@ -0,0 +1,146 @@ @@ -0,0 +1,146 @@
// CSharp Editor Example with Code Completion
// Copyright (c) 2007, 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.Text;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Dom.CSharp;
using TextEditor = ICSharpCode.TextEditor;
using NRefactoryResolver = ICSharpCode.SharpDevelop.Dom.NRefactoryResolver.NRefactoryResolver;
namespace CSharpEditor
{
sealed class ToolTipProvider
{
MainForm mainForm;
TextEditor.TextEditorControl editor;
CSharpExpressionFinder expressionFinder = new CSharpExpressionFinder(MainForm.DummyFileName);
private ToolTipProvider(MainForm mainForm, TextEditor.TextEditorControl editor)
{
this.mainForm = mainForm;
this.editor = editor;
}
public static void Attach(MainForm mainForm, TextEditor.TextEditorControl editor)
{
ToolTipProvider tp = new ToolTipProvider(mainForm, editor);
editor.ActiveTextAreaControl.TextArea.ToolTipRequest += tp.OnToolTipRequest;
}
void OnToolTipRequest(object sender, TextEditor.ToolTipRequestEventArgs e)
{
if (e.InDocument && !e.ToolTipShown) {
// SD2 requires subtracting 1 from the offset, this is fixed in the expression
// finder in SD3.
ExpressionResult expression = expressionFinder.FindFullExpression(
editor.Text,
editor.Document.PositionToOffset(e.LogicalPosition) - 1);
TextEditor.TextArea textArea = editor.ActiveTextAreaControl.TextArea;
NRefactoryResolver resolver = new NRefactoryResolver(mainForm.myProjectContent, mainForm.myProjectContent.Language);
ResolveResult rr = resolver.Resolve(expression,
textArea.Caret.Line,
textArea.Caret.Column,
MainForm.DummyFileName,
textArea.MotherTextEditorControl.Text);
string toolTipText = GetText(rr);
if (toolTipText != null) {
e.ShowToolTip(toolTipText);
}
}
}
static string GetText(ResolveResult result)
{
if (result == null) {
return null;
}
if (result is MixedResolveResult)
return GetText(((MixedResolveResult)result).PrimaryResult);
IAmbience ambience = new CSharpAmbience();
ambience.ConversionFlags = ConversionFlags.StandardConversionFlags | ConversionFlags.ShowAccessibility;
if (result is MemberResolveResult) {
return GetMemberText(ambience, ((MemberResolveResult)result).ResolvedMember);
} else if (result is LocalResolveResult) {
LocalResolveResult rr = (LocalResolveResult)result;
ambience.ConversionFlags = ConversionFlags.UseFullyQualifiedNames
| ConversionFlags.ShowReturnType
| ConversionFlags.QualifiedNamesOnlyForReturnTypes;
StringBuilder b = new StringBuilder();
if (rr.IsParameter)
b.Append("parameter ");
else
b.Append("local variable ");
b.Append(ambience.Convert(rr.Field));
return b.ToString();
} else if (result is NamespaceResolveResult) {
return "namespace " + ((NamespaceResolveResult)result).Name;
} else if (result is TypeResolveResult) {
IClass c = ((TypeResolveResult)result).ResolvedClass;
if (c != null)
return GetMemberText(ambience, c);
else
return ambience.Convert(result.ResolvedType);
} else if (result is MethodResolveResult) {
MethodResolveResult mrr = result as MethodResolveResult;
IMethod m = mrr.GetMethodIfSingleOverload();
if (m != null)
return GetMemberText(ambience, m);
else
return "Overload of " + ambience.Convert(mrr.ContainingType) + "." + mrr.Name;
} else {
return null;
}
}
static string GetMemberText(IAmbience ambience, IDecoration member)
{
StringBuilder text = new StringBuilder();
if (member is IField) {
text.Append(ambience.Convert(member as IField));
} else if (member is IProperty) {
text.Append(ambience.Convert(member as IProperty));
} else if (member is IEvent) {
text.Append(ambience.Convert(member as IEvent));
} else if (member is IMethod) {
text.Append(ambience.Convert(member as IMethod));
} else if (member is IClass) {
text.Append(ambience.Convert(member as IClass));
} else {
text.Append("unknown member ");
text.Append(member.ToString());
}
string documentation = member.Documentation;
if (documentation != null && documentation.Length > 0) {
text.Append('\n');
text.Append(CodeCompletionData.XmlDocumentationToText(documentation));
}
return text.ToString();
}
}
}
Loading…
Cancel
Save