Browse Source

add basic DebuggerDotCompletion implementation

pull/331/head
Siegfried Pammer 12 years ago
parent
commit
8052516145
  1. 13
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpLanguageBinding.cs
  2. 59
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/CSharpCompletionBinding.cs
  3. 32
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/CSharpCompletionContext.cs
  4. 1
      src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.csproj
  5. 37
      src/AddIns/Debugger/Debugger.AddIn/Pads/AutoCompleteTextBox.cs
  6. 128
      src/AddIns/Debugger/Debugger.AddIn/Pads/DebuggerDotCompletion.cs
  7. 10
      src/Main/Base/Project/Src/Services/LanguageBinding/DefaultLanguageBinding.cs
  8. 10
      src/Main/Base/Project/Src/Services/LanguageBinding/ILanguageBinding.cs

13
src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpLanguageBinding.cs

@ -18,12 +18,12 @@ @@ -18,12 +18,12 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.Design;
using ICSharpCode.NRefactory;
using ICSharpCode.SharpDevelop.Editor.CodeCompletion;
using CSharpBinding.Completion;
using CSharpBinding.FormattingStrategy;
using CSharpBinding.Refactoring;
using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.AvalonEdit.Rendering;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Editor;
@ -43,6 +43,13 @@ namespace CSharpBinding @@ -43,6 +43,13 @@ namespace CSharpBinding
this.container.AddService(typeof(CodeGenerator), new CSharpCodeGenerator());
this.container.AddService(typeof(System.CodeDom.Compiler.CodeDomProvider), new Microsoft.CSharp.CSharpCodeProvider());
}
public override ICodeCompletionBinding CreateCompletionBinding(FileName fileName, TextLocation currentLocation, ICSharpCode.NRefactory.Editor.ITextSource fileContent)
{
if (fileName == null)
throw new ArgumentNullException("fileName");
return new CSharpCompletionBinding(fileName, currentLocation, fileContent);
}
}
public class CSharpTextEditorExtension : ITextEditorExtension

59
src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/CSharpCompletionBinding.cs

@ -20,10 +20,14 @@ using System; @@ -20,10 +20,14 @@ using System;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.Core;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.Completion;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.Completion;
using ICSharpCode.NRefactory.Editor;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Editor.CodeCompletion;
@ -32,6 +36,22 @@ namespace CSharpBinding.Completion @@ -32,6 +36,22 @@ namespace CSharpBinding.Completion
{
public class CSharpCompletionBinding : ICodeCompletionBinding
{
FileName contextFileName;
TextLocation currentLocation;
ITextSource fileContent;
public CSharpCompletionBinding()
: this(null, TextLocation.Empty, null)
{
}
public CSharpCompletionBinding(FileName contextFileName, TextLocation currentLocation, ITextSource fileContent)
{
this.contextFileName = contextFileName;
this.currentLocation = currentLocation;
this.fileContent = fileContent;
}
public CodeCompletionKeyPressResult HandleKeyPress(ITextEditor editor, char ch)
{
// We use HandleKeyPressed instead.
@ -52,36 +72,49 @@ namespace CSharpBinding.Completion @@ -52,36 +72,49 @@ namespace CSharpBinding.Completion
bool ShowCompletion(ITextEditor editor, char completionChar, bool ctrlSpace)
{
var completionContext = CSharpCompletionContext.Get(editor);
CSharpCompletionContext completionContext;
if (fileContent == null) {
completionContext = CSharpCompletionContext.Get(editor);
} else {
completionContext = CSharpCompletionContext.Get(editor, fileContent, currentLocation, contextFileName);
}
if (completionContext == null)
return false;
int caretOffset;
if (fileContent == null) {
caretOffset = editor.Caret.Offset;
currentLocation = editor.Caret.Location;
} else {
caretOffset = completionContext.Document.GetOffset(currentLocation);
}
var completionFactory = new CSharpCompletionDataFactory(completionContext, new CSharpResolver(completionContext.TypeResolveContextAtCaret));
CSharpCompletionEngine cce = new CSharpCompletionEngine(
editor.Document,
completionContext.Document,
completionContext.CompletionContextProvider,
completionFactory,
completionContext.ProjectContent,
completionContext.TypeResolveContextAtCaret
);
cce.FormattingPolicy = FormattingOptionsFactory.CreateSharpDevelop();
cce.EolMarker = DocumentUtilities.GetLineTerminator(editor.Document, editor.Caret.Line);
cce.IndentString = editor.Options.IndentationString;
cce.EolMarker = DocumentUtilities.GetLineTerminator(completionContext.Document, currentLocation.Line);
cce.IndentString = editor.Options.IndentationString;
int startPos, triggerWordLength;
IEnumerable<ICompletionData> completionData;
if (ctrlSpace) {
if (!cce.TryGetCompletionWord(editor.Caret.Offset, out startPos, out triggerWordLength)) {
startPos = editor.Caret.Offset;
if (!cce.TryGetCompletionWord(caretOffset, out startPos, out triggerWordLength)) {
startPos = caretOffset;
triggerWordLength = 0;
}
completionData = cce.GetCompletionData(startPos, true);
completionData = completionData.Concat(cce.GetImportCompletionData(startPos));
} else {
startPos = editor.Caret.Offset;
startPos = caretOffset;
if (char.IsLetterOrDigit (completionChar) || completionChar == '_') {
if (startPos > 1 && char.IsLetterOrDigit (editor.Document.GetCharAt (startPos - 2)))
if (startPos > 1 && char.IsLetterOrDigit (completionContext.Document.GetCharAt (startPos - 2)))
return false;
completionData = cce.GetCompletionData(startPos, false);
startPos--;
@ -96,8 +129,8 @@ namespace CSharpBinding.Completion @@ -96,8 +129,8 @@ namespace CSharpBinding.Completion
list.Items.AddRange(FilterAndAddTemplates(editor, completionData.Cast<ICompletionItem>().ToList()));
if (list.Items.Count > 0) {
list.SortItems();
list.PreselectionLength = editor.Caret.Offset - startPos;
list.PostselectionLength = Math.Max(0, startPos + triggerWordLength - editor.Caret.Offset);
list.PreselectionLength = caretOffset - startPos;
list.PostselectionLength = Math.Max(0, startPos + triggerWordLength - caretOffset);
list.SuggestedItem = list.Items.FirstOrDefault(i => i.Text == cce.DefaultCompletionString);
editor.ShowCompletionWindow(list);
return true;
@ -106,13 +139,13 @@ namespace CSharpBinding.Completion @@ -106,13 +139,13 @@ namespace CSharpBinding.Completion
if (!ctrlSpace) {
// Method Insight
var pce = new CSharpParameterCompletionEngine(
editor.Document,
completionContext.Document,
completionContext.CompletionContextProvider,
completionFactory,
completionContext.ProjectContent,
completionContext.TypeResolveContextAtCaret
);
var newInsight = pce.GetParameterDataProvider(editor.Caret.Offset, completionChar) as CSharpMethodInsight;
var newInsight = pce.GetParameterDataProvider(caretOffset, completionChar) as CSharpMethodInsight;
if (newInsight != null && newInsight.items.Count > 0) {
newInsight.UpdateHighlightedParameter(pce);
newInsight.Show();

32
src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/CSharpCompletionContext.cs

@ -18,6 +18,10 @@ @@ -18,6 +18,10 @@
using System;
using System.Diagnostics;
using ICSharpCode.Core;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.Editor;
using ICSharpCode.SharpDevelop.Project;
using CSharpBinding.Parser;
using ICSharpCode.NRefactory.CSharp.Completion;
using ICSharpCode.NRefactory.CSharp.TypeSystem;
@ -30,6 +34,7 @@ namespace CSharpBinding.Completion @@ -30,6 +34,7 @@ namespace CSharpBinding.Completion
sealed class CSharpCompletionContext
{
public readonly ITextEditor Editor;
public readonly IDocument Document;
public readonly CSharpFullParseInformation ParseInformation;
public readonly ICompilation Compilation;
public readonly IProjectContent ProjectContent;
@ -51,21 +56,40 @@ namespace CSharpBinding.Completion @@ -51,21 +56,40 @@ namespace CSharpBinding.Completion
if (projectContent == null)
return null;
return new CSharpCompletionContext(editor, parseInfo, compilation, projectContent);
return new CSharpCompletionContext(editor, parseInfo, compilation, projectContent, editor.Document, editor.Caret.Location);
}
private CSharpCompletionContext(ITextEditor editor, CSharpFullParseInformation parseInfo, ICompilation compilation, IProjectContent projectContent)
public static CSharpCompletionContext Get(ITextEditor editor, ITextSource fileContent, TextLocation currentLocation, FileName fileName)
{
IDocument document = new ReadOnlyDocument(fileContent);
// Don't require the very latest parse information, an older cached version is OK.
var parseInfo = SD.ParserService.Parse(fileName, document) as CSharpFullParseInformation;
if (parseInfo == null)
return null;
ICompilation compilation = SD.ParserService.GetCompilationForFile(fileName);
var projectContent = compilation.MainAssembly.UnresolvedAssembly as IProjectContent;
if (projectContent == null)
return null;
return new CSharpCompletionContext(editor, parseInfo, compilation, projectContent, document, currentLocation);
}
private CSharpCompletionContext(ITextEditor editor, CSharpFullParseInformation parseInfo, ICompilation compilation, IProjectContent projectContent, IDocument document, TextLocation caretLocation)
{
Debug.Assert(editor != null);
Debug.Assert(parseInfo != null);
Debug.Assert(compilation != null);
Debug.Assert(projectContent != null);
Debug.Assert(document != null);
this.Editor = editor;
this.Document = document;
this.ParseInformation = parseInfo;
this.Compilation = compilation;
this.ProjectContent = projectContent;
this.TypeResolveContextAtCaret = parseInfo.UnresolvedFile.GetTypeResolveContext(compilation, editor.Caret.Location);
this.CompletionContextProvider = new DefaultCompletionContextProvider(editor.Document, parseInfo.UnresolvedFile);
this.TypeResolveContextAtCaret = parseInfo.UnresolvedFile.GetTypeResolveContext(compilation, caretLocation);
this.CompletionContextProvider = new DefaultCompletionContextProvider(document, parseInfo.UnresolvedFile);
}
}
}

1
src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.csproj

@ -112,6 +112,7 @@ @@ -112,6 +112,7 @@
<SubType>Code</SubType>
</Compile>
<Compile Include="Pads\ClassBrowserSupport.cs" />
<Compile Include="Pads\DebuggerDotCompletion.cs" />
<Compile Include="Pads\WatchPadCommands.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Options\DebuggingOptions.cs" />

37
src/AddIns/Debugger/Debugger.AddIn/Pads/AutoCompleteTextBox.cs

@ -17,6 +17,7 @@ @@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
@ -24,6 +25,13 @@ using System.Windows.Media; @@ -24,6 +25,13 @@ using System.Windows.Media;
using System.Windows.Threading;
using ICSharpCode.AvalonEdit;
using ICSharpCode.AvalonEdit.Editing;
using ICSharpCode.Core;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.Completion;
using ICSharpCode.NRefactory.CSharp.Refactoring;
using ICSharpCode.NRefactory.Editor;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Editor.CodeCompletion;
@ -113,33 +121,14 @@ namespace Debugger.AddIn.Pads.Controls @@ -113,33 +121,14 @@ namespace Debugger.AddIn.Pads.Controls
{
StackFrame frame = WindowsDebugger.CurrentStackFrame;
if (e.Text == "." && frame != null)
ShowDotCompletion(frame, this.editor.Text);
ShowDotCompletion(frame);
}
private void ShowDotCompletion(StackFrame frame, string currentText)
void ShowDotCompletion(StackFrame frame)
{
string language = ProjectService.CurrentProject == null ? "C#" : ProjectService.CurrentProject.Language;
#warning reimplement this!
// NRefactoryResolver resolver = new NRefactoryResolver(LanguageProperties.GetLanguage(language));
//
// var seg = frame.NextStatement;
//
// var expressionFinder = ParserService.GetExpressionFinder(seg.Filename);
// var info = ParserService.GetParseInformation(seg.Filename);
//
// string text = ParserService.GetParseableFileContent(seg.Filename).Text;
//
// int currentOffset = this.editor.CaretOffset;
//
// var expr = expressionFinder.FindExpression(currentText, currentOffset);
//
// expr.Region = new DomRegion(seg.StartLine, seg.StartColumn, seg.EndLine, seg.EndColumn);
//
// var rr = resolver.Resolve(expr, info, text);
//
// if (rr != null) {
// editorAdapter.ShowCompletionWindow(new DotCodeCompletionItemProvider().GenerateCompletionListForResolveResult(rr, expr.Context));
// }
var binding = DebuggerDotCompletion.PrepareDotCompletion(editor.Text.Substring(0, editor.CaretOffset), frame);
if (binding == null) return;
binding.HandleKeyPressed(editorAdapter, '.');
}
public void FocusEditor()

128
src/AddIns/Debugger/Debugger.AddIn/Pads/DebuggerDotCompletion.cs

@ -0,0 +1,128 @@ @@ -0,0 +1,128 @@
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Text;
using ICSharpCode.Core;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.Refactoring;
using ICSharpCode.NRefactory.Editor;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Editor.CodeCompletion;
namespace Debugger.AddIn.Pads.Controls
{
static class DebuggerDotCompletion
{
public static ICodeCompletionBinding PrepareDotCompletion(string expressionToComplete, StackFrame context)
{
var seq = context.NextStatement;
var fileName = new FileName(seq.Filename);
var lang = SD.LanguageService.GetLanguageByFileName(fileName);
var currentLocation = new TextLocation(seq.StartLine, seq.StartColumn);
if (lang == null)
return null;
string content = GeneratePartialClassContextStub(fileName, currentLocation, context);
const string caretPoint = "$__Caret_Point__$;";
int caretOffset = content.IndexOf(caretPoint, StringComparison.Ordinal) + expressionToComplete.Length;
var doc = new ReadOnlyDocument(content.Replace(caretPoint, expressionToComplete));
return lang.CreateCompletionBinding(fileName, doc.GetLocation(caretOffset), doc.CreateSnapshot());
}
static string GeneratePartialClassContextStub(FileName fileName, TextLocation currentLocation, StackFrame context)
{
var compilation = SD.ParserService.GetCompilationForFile(fileName);
var file = SD.ParserService.GetExistingUnresolvedFile(fileName);
if (compilation == null || file == null)
return "";
var member = file.GetMember(currentLocation);
if (member == null)
return "";
var builder = new TypeSystemAstBuilder();
EntityDeclaration decl = builder.ConvertEntity(member.Resolve(new SimpleTypeResolveContext(compilation.MainAssembly)));
decl.Name = "__DebuggerStub_" + decl.Name;
decl.Modifiers &= (Modifiers.Static);
switch (member.SymbolKind) {
case SymbolKind.Property:
break;
case SymbolKind.Indexer:
break;
case SymbolKind.Event:
break;
case SymbolKind.Method:
GenerateBodyFromContext(builder, context, (MethodDeclaration)decl);
break;
case SymbolKind.Operator:
break;
case SymbolKind.Constructor:
break;
case SymbolKind.Destructor:
break;
case SymbolKind.Accessor:
break;
default:
throw new ArgumentOutOfRangeException();
}
return WrapInType(member.DeclaringTypeDefinition, decl.ToString());
}
static void GenerateBodyFromContext(TypeSystemAstBuilder builder, StackFrame context, MethodDeclaration methodDeclaration)
{
methodDeclaration.Body = new BlockStatement();
foreach (var v in context.GetLocalVariables())
methodDeclaration.Body.Statements.Add(new VariableDeclarationStatement(builder.ConvertType(v.Type), v.Name));
methodDeclaration.Body.Statements.Add(new ExpressionStatement(new IdentifierExpression("$__Caret_Point__$")));
}
static string WrapInType(IUnresolvedTypeDefinition entity, string code)
{
if (entity == null)
return code;
code = WrapInType(entity.DeclaringTypeDefinition, GetHeader(entity) + code + "\r\n}");
if (entity.DeclaringTypeDefinition == null) {
return "namespace " + entity.Namespace + " {\r\n" + code + "\r\n}";
}
return code;
}
static string GetHeader(IUnresolvedTypeDefinition entity)
{
StringBuilder builder = new StringBuilder();
builder.Append("partial ");
switch (entity.Kind) {
case TypeKind.Class:
builder.Append("class ");
break;
case TypeKind.Interface:
builder.Append("interface ");
break;
case TypeKind.Struct:
builder.Append("struct ");
break;
default:
throw new NotSupportedException();
}
builder.Append(entity.Name);
builder.AppendLine(" {");
return builder.ToString();
}
}
}

10
src/Main/Base/Project/Src/Services/LanguageBinding/DefaultLanguageBinding.cs

@ -18,7 +18,12 @@ @@ -18,7 +18,12 @@
using System;
using System.ComponentModel.Design;
using ICSharpCode.Core;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.Editor;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Editor.CodeCompletion;
using ICSharpCode.SharpDevelop.Refactoring;
namespace ICSharpCode.SharpDevelop
@ -70,6 +75,11 @@ namespace ICSharpCode.SharpDevelop @@ -70,6 +75,11 @@ namespace ICSharpCode.SharpDevelop
}
}
public virtual ICodeCompletionBinding CreateCompletionBinding(FileName fileName, TextLocation currentLocation, ITextSource fileContent)
{
throw new NotSupportedException();
}
public object GetService(Type serviceType)
{
return container.GetService(serviceType);

10
src/Main/Base/Project/Src/Services/LanguageBinding/ILanguageBinding.cs

@ -17,7 +17,12 @@ @@ -17,7 +17,12 @@
// DEALINGS IN THE SOFTWARE.
using System;
using ICSharpCode.Core;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.Editor;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Editor.CodeCompletion;
using ICSharpCode.SharpDevelop.Refactoring;
namespace ICSharpCode.SharpDevelop
@ -55,5 +60,10 @@ namespace ICSharpCode.SharpDevelop @@ -55,5 +60,10 @@ namespace ICSharpCode.SharpDevelop
System.CodeDom.Compiler.CodeDomProvider CodeDomProvider {
get;
}
/// <summary>
/// Creates a completion binding which works with a fileName and a location as context.
/// </summary>
ICodeCompletionBinding CreateCompletionBinding(FileName fileName, TextLocation currentLocation, ITextSource fileContent);
}
}

Loading…
Cancel
Save