diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/Project/AspNet.Mvc.addin b/src/AddIns/BackendBindings/AspNet.Mvc/Project/AspNet.Mvc.addin index 8f012b7a71..2b878a57fb 100644 --- a/src/AddIns/BackendBindings/AspNet.Mvc/Project/AspNet.Mvc.addin +++ b/src/AddIns/BackendBindings/AspNet.Mvc/Project/AspNet.Mvc.addin @@ -130,7 +130,7 @@ - + diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/Project/AspNet.Mvc.csproj b/src/AddIns/BackendBindings/AspNet.Mvc/Project/AspNet.Mvc.csproj index a6d3b5fd9d..0ac77f3dba 100644 --- a/src/AddIns/BackendBindings/AspNet.Mvc/Project/AspNet.Mvc.csproj +++ b/src/AddIns/BackendBindings/AspNet.Mvc/Project/AspNet.Mvc.csproj @@ -285,6 +285,11 @@ ICSharpCode.AvalonEdit False + + {53DCA265-3C3C-42F9-B647-F72BA678122B} + ICSharpCode.NRefactory.CSharp + False + {3B2A5653-EC97-4001-BB9B-D90F1AF2C371} ICSharpCode.NRefactory diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpCompletionBinding.cs b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpCompletionBinding.cs index 4401cdb541..38b0020cb6 100644 --- a/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpCompletionBinding.cs +++ b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpCompletionBinding.cs @@ -16,27 +16,122 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -//using System; -//using ICSharpCode.SharpDevelop.Editor; -//using ICSharpCode.SharpDevelop.Editor.CodeCompletion; -// -//namespace ICSharpCode.AspNet.Mvc.Completion -//{ -// public class RazorCSharpCompletionBinding : DefaultCodeCompletionBinding -// { -// public RazorCSharpCompletionBinding() -// { -// } -// -// public override CodeCompletionKeyPressResult HandleKeyPress(ITextEditor editor, char ch) -// { -// if (ch == '.') { -// new RazorCSharpDotCompletionDataProvider().ShowCompletion(editor); -// return CodeCompletionKeyPressResult.Completed; -// } else if (ch == '(') { -// return base.HandleKeyPress(editor, ch); -// } -// return CodeCompletionKeyPressResult.None; -// } -// } -//} +using System; +using System.IO; +using ICSharpCode.NRefactory; +using ICSharpCode.NRefactory.CSharp.Resolver; +using ICSharpCode.NRefactory.CSharp.TypeSystem; +using ICSharpCode.NRefactory.TypeSystem; +using ICSharpCode.NRefactory.TypeSystem.Implementation; +using ICSharpCode.SharpDevelop; +using ICSharpCode.SharpDevelop.Editor; +using ICSharpCode.SharpDevelop.Editor.CodeCompletion; + +namespace ICSharpCode.AspNet.Mvc.Completion +{ + public class RazorCSharpCompletionBinding : ICodeCompletionBinding + { + public bool HandleKeyPressed(ITextEditor editor, char ch) + { + if (ch == '.') { + var binding = CreateBinding(editor); + return binding.HandleKeyPressed(editor, ch); + } + return false; + } + + public bool CtrlSpace(ITextEditor editor) + { + return false; + } + + public CodeCompletionKeyPressResult HandleKeyPress(ITextEditor editor, char ch) + { + // We use HandleKeyPressed instead. + return CodeCompletionKeyPressResult.None; + } + + ICodeCompletionBinding CreateBinding(ITextEditor editor) + { + return SD.LanguageService.GetLanguageByExtension(".cs") + .CreateCompletionBinding(FindExpressionToComplete(editor), CreateContext(editor)); + } + + string FindExpressionToComplete(ITextEditor editor) + { + int endOffset = editor.Caret.Offset; + int startOffset = endOffset; + while (startOffset > 0 && IsValidCharacter(editor.Document.GetCharAt(startOffset - 1))) + startOffset--; + return editor.Document.GetText(startOffset, endOffset - startOffset); + } + + bool IsValidCharacter(char ch) + { + return Char.IsLetterOrDigit(ch) || + (ch == '.') || + (ch == '_'); + } + + ICodeContext CreateContext(ITextEditor editor) + { + var compilation = SD.ParserService.GetCompilationForFile(editor.FileName); + var project = SD.ProjectService.FindProjectContainingFile(editor.FileName); + + var resolveContext = new SimpleTypeResolveContext(compilation.MainAssembly); + + var currentTypeDefinition = new DefaultUnresolvedTypeDefinition(project.RootNamespace, Path.GetFileNameWithoutExtension(editor.FileName)); + ITypeReference baseTypeReference = new GetClassTypeReference("System.Web.Mvc", "WebViewPage", 1); + baseTypeReference = new ParameterizedTypeReference(baseTypeReference, new[] { KnownTypeReference.Object }); + currentTypeDefinition.BaseTypes.Add(baseTypeReference); + + var currentMethod = new DefaultUnresolvedMethod(currentTypeDefinition, "__ContextStub__"); + currentMethod.ReturnType = KnownTypeReference.Void; + currentTypeDefinition.Members.Add(currentMethod); + + var currentResolvedTypeDef = new DefaultResolvedTypeDefinition(resolveContext, currentTypeDefinition); + + var projectContent = compilation.MainAssembly.UnresolvedAssembly as IProjectContent; + + var currentFile = new CSharpUnresolvedFile(); + + currentFile.RootUsingScope.AddSimpleUsing("System.Web.Mvc"); + currentFile.RootUsingScope.AddSimpleUsing("System.Web.Mvc.Ajax"); + currentFile.RootUsingScope.AddSimpleUsing("System.Web.Mvc.Html"); + currentFile.RootUsingScope.AddSimpleUsing("System.Web.Routing"); + + currentFile.TopLevelTypeDefinitions.Add(currentTypeDefinition); + + if (projectContent != null) { + compilation = projectContent.AddOrUpdateFiles(currentFile).CreateCompilation(SD.ParserService.GetCurrentSolutionSnapshot()); + } + + var context = new CSharpTypeResolveContext(compilation.MainAssembly, + currentFile.RootUsingScope.Resolve(compilation), + currentResolvedTypeDef, + currentMethod.CreateResolved(resolveContext.WithCurrentTypeDefinition(currentResolvedTypeDef))); + return new CSharpResolver(context); + } + } + + static class NRUtils + { + /// Does not support type arguments! + public static void AddSimpleUsing(this UsingScope scope, string fullName) + { + if (scope == null) + throw new ArgumentNullException("scope"); + string[] parts = fullName.Trim().Split('.'); + TypeOrNamespaceReference reference = null; + foreach (var part in parts) { + if (reference != null) { + reference = new MemberTypeOrNamespaceReference(reference, part, EmptyList.Instance); + } else { + reference = new SimpleTypeOrNamespaceReference(part, EmptyList.Instance); + } + } + + scope.Usings.AddIfNotNull(reference); + } + } +} diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpLanguageBinding.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpLanguageBinding.cs index 548fddd585..8921e09daf 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpLanguageBinding.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpLanguageBinding.cs @@ -55,35 +55,26 @@ namespace CSharpBinding this.container.AddService(typeof(System.CodeDom.Compiler.CodeDomProvider), new Microsoft.CSharp.CSharpCodeProvider()); } - public override ICodeCompletionBinding CreateCompletionBinding(string expressionToComplete, FileName fileName, TextLocation location, ICodeContext context) + public override ICodeCompletionBinding CreateCompletionBinding(string expressionToComplete, ICodeContext context) { - if (fileName == null) - throw new ArgumentNullException("fileName"); if (context == null) throw new ArgumentNullException("context"); - string content = GeneratePartialClassContextStub(fileName, location, context); + string content = GeneratePartialClassContextStub(context); const string caretPoint = "$__Caret_Point__$;"; int caretOffset = content.IndexOf(caretPoint, StringComparison.Ordinal) + expressionToComplete.Length; SD.Log.DebugFormatted("context used for dot completion: {0}", content.Replace(caretPoint, "$" + expressionToComplete + "|$")); var doc = new ReadOnlyDocument(content.Replace(caretPoint, expressionToComplete)); - return new CSharpCompletionBinding(fileName, doc.GetLocation(caretOffset), doc.CreateSnapshot()); + return new CSharpCompletionBinding(context, doc.GetLocation(caretOffset), doc.CreateSnapshot()); } - static string GeneratePartialClassContextStub(FileName fileName, TextLocation location, ICodeContext context) + static string GeneratePartialClassContextStub(ICodeContext context) { - var compilation = SD.ParserService.GetCompilationForFile(fileName); - var file = SD.ParserService.GetExistingUnresolvedFile(fileName); - if (compilation == null || file == null) - return ""; - var unresolvedMember = file.GetMember(location); - if (unresolvedMember == null) - return ""; - var member = unresolvedMember.Resolve(new SimpleTypeResolveContext(compilation.MainAssembly)); + var member = context.CurrentMember; if (member == null) return ""; var builder = new TypeSystemAstBuilder(); MethodDeclaration decl; - if (unresolvedMember is IMethod) { + if (member is IMethod) { // If it's a method, convert it directly (including parameters + type parameters) decl = (MethodDeclaration)builder.ConvertEntity(member); } else { @@ -97,11 +88,11 @@ namespace CSharpBinding } decl.Name = "__DebuggerStub__"; decl.ReturnType = builder.ConvertType(member.ReturnType); - decl.Modifiers = unresolvedMember.IsStatic ? Modifiers.Static : Modifiers.None; + decl.Modifiers = member.IsStatic ? Modifiers.Static : Modifiers.None; // Make the method look like an explicit interface implementation so that it doesn't appear in CC decl.PrivateImplementationType = new SimpleType("__DummyType__"); decl.Body = GenerateBodyFromContext(builder, context.LocalVariables.ToArray()); - return WrapInType(unresolvedMember.DeclaringTypeDefinition, decl).ToString(); + return WrapInType(context.CurrentTypeDefinition, decl).ToString(); } static BlockStatement GenerateBodyFromContext(TypeSystemAstBuilder builder, IVariable[] variables) @@ -113,7 +104,7 @@ namespace CSharpBinding return body; } - static AstNode WrapInType(IUnresolvedTypeDefinition entity, EntityDeclaration decl) + static AstNode WrapInType(ITypeDefinition entity, EntityDeclaration decl) { if (entity == null) return decl; @@ -137,7 +128,7 @@ namespace CSharpBinding }; } - static ClassType GetClassType(IUnresolvedTypeDefinition entity) + static ClassType GetClassType(ITypeDefinition entity) { switch (entity.Kind) { case TypeKind.Interface: diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/CSharpCompletionBinding.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/CSharpCompletionBinding.cs index 1e9943d962..11bbd494da 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/CSharpCompletionBinding.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/CSharpCompletionBinding.cs @@ -26,6 +26,7 @@ using ICSharpCode.NRefactory.CSharp.Resolver; using ICSharpCode.NRefactory.Completion; 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; @@ -35,7 +36,7 @@ namespace CSharpBinding.Completion { public class CSharpCompletionBinding : ICodeCompletionBinding { - FileName contextFileName; + ICodeContext context; TextLocation currentLocation; ITextSource fileContent; @@ -44,9 +45,9 @@ namespace CSharpBinding.Completion { } - public CSharpCompletionBinding(FileName contextFileName, TextLocation currentLocation, ITextSource fileContent) + public CSharpCompletionBinding(ICodeContext context, TextLocation currentLocation, ITextSource fileContent) { - this.contextFileName = contextFileName; + this.context = context; this.currentLocation = currentLocation; this.fileContent = fileContent; } @@ -75,7 +76,7 @@ namespace CSharpBinding.Completion if (fileContent == null) { completionContext = CSharpCompletionContext.Get(editor); } else { - completionContext = CSharpCompletionContext.Get(editor, fileContent, currentLocation, contextFileName); + completionContext = CSharpCompletionContext.Get(editor, context, currentLocation, fileContent); } if (completionContext == null) return false; diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/CSharpCompletionContext.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/CSharpCompletionContext.cs index ae654a0d81..2f4623dcf7 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/CSharpCompletionContext.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/CSharpCompletionContext.cs @@ -61,38 +61,24 @@ namespace CSharpBinding.Completion return new CSharpCompletionContext(editor, parseInfo.SyntaxTree.ConditionalSymbols, compilation, projectContent, editor.Document, parseInfo.UnresolvedFile, editor.Caret.Location); } - public static CSharpCompletionContext Get(ITextEditor editor, ITextSource fileContent, TextLocation currentLocation, FileName fileName) + public static CSharpCompletionContext Get(ITextEditor editor, ICodeContext context, TextLocation currentLocation, ITextSource fileContent) { IDocument document = new ReadOnlyDocument(fileContent); - // Don't require the very latest parse information, an older cached version is OK. - var parseInfo = SD.ParserService.GetCachedParseInformation(fileName) as CSharpFullParseInformation; - if (parseInfo == null) { - parseInfo = SD.ParserService.Parse(fileName) as CSharpFullParseInformation; - } - if (parseInfo == null) - return null; - - - var project = SD.ProjectService.FindProjectContainingFile(fileName)as CSharpProject; - if (project == null) - return null; - - var solutionSnapshot = SD.ParserService.GetCurrentSolutionSnapshot(); - var projectContent = solutionSnapshot.GetProjectContent(project); + var projectContent = context.Compilation.MainAssembly.UnresolvedAssembly as IProjectContent; if (projectContent == null) return null; - CSharpParser parser = new CSharpParser(project.CompilerSettings); + CSharpParser parser = new CSharpParser(); parser.GenerateTypeSystemMode = false; SyntaxTree cu = parser.Parse(fileContent, Path.GetRandomFileName() + ".cs"); cu.Freeze(); CSharpUnresolvedFile unresolvedFile = cu.ToTypeSystem(); - ICompilation compilation = projectContent.AddOrUpdateFiles(unresolvedFile).CreateCompilation(solutionSnapshot); + ICompilation compilation = projectContent.AddOrUpdateFiles(unresolvedFile).CreateCompilation(SD.ParserService.GetCurrentSolutionSnapshot()); - return new CSharpCompletionContext(editor, parseInfo.SyntaxTree.ConditionalSymbols, compilation, projectContent, document, unresolvedFile, currentLocation); + return new CSharpCompletionContext(editor, EmptyList.Instance, compilation, projectContent, document, unresolvedFile, currentLocation); } private CSharpCompletionContext(ITextEditor editor, IList conditionalSymbols, ICompilation compilation, IProjectContent projectContent, IDocument document, CSharpUnresolvedFile unresolvedFile, TextLocation caretLocation) diff --git a/src/AddIns/Debugger/Debugger.AddIn/Pads/AutoCompleteTextBox.cs b/src/AddIns/Debugger/Debugger.AddIn/Pads/AutoCompleteTextBox.cs index aca8f0c0b6..b931e96c10 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Pads/AutoCompleteTextBox.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Pads/AutoCompleteTextBox.cs @@ -134,7 +134,7 @@ namespace Debugger.AddIn.Pads.Controls ContextTextLocation = new TextLocation(frame.NextStatement.StartLine, frame.NextStatement.StartColumn); } if (ContextFileName == null) return; - var binding = DebuggerDotCompletion.PrepareDotCompletion(editor.Text.Substring(0, editor.CaretOffset), ContextFileName, ContextTextLocation, SD.ParserService.ResolveContext(ContextFileName, ContextTextLocation)); + var binding = DebuggerDotCompletion.PrepareDotCompletion(editor.Text.Substring(0, editor.CaretOffset), SD.ParserService.ResolveContext(ContextFileName, ContextTextLocation)); if (binding == null) return; binding.HandleKeyPressed(editorAdapter, '.'); } else { diff --git a/src/AddIns/Debugger/Debugger.AddIn/Pads/ConsolePad.cs b/src/AddIns/Debugger/Debugger.AddIn/Pads/ConsolePad.cs index c88df18834..76c3341a9d 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Pads/ConsolePad.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Pads/ConsolePad.cs @@ -88,7 +88,7 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads { var fileName = new ICSharpCode.Core.FileName(frame.NextStatement.Filename); var textLocation = new TextLocation(frame.NextStatement.StartLine, frame.NextStatement.StartColumn); - var binding = DebuggerDotCompletion.PrepareDotCompletion(currentText, fileName, textLocation, SD.ParserService.ResolveContext(fileName, textLocation)); + var binding = DebuggerDotCompletion.PrepareDotCompletion(currentText, SD.ParserService.ResolveContext(fileName, textLocation)); if (binding == null) return; binding.HandleKeyPressed(console.TextEditor, '.'); } diff --git a/src/AddIns/Debugger/Debugger.AddIn/Pads/DebuggerDotCompletion.cs b/src/AddIns/Debugger/Debugger.AddIn/Pads/DebuggerDotCompletion.cs index 854abc5cca..9370726b9d 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Pads/DebuggerDotCompletion.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Pads/DebuggerDotCompletion.cs @@ -41,12 +41,10 @@ namespace Debugger.AddIn.Pads.Controls return !errors.Any(); } - public static ICodeCompletionBinding PrepareDotCompletion(string expressionToComplete, FileName fileName, TextLocation location, ICodeContext context) + public static ICodeCompletionBinding PrepareDotCompletion(string expressionToComplete, ICodeContext context) { - var lang = SD.LanguageService.GetLanguageByFileName(fileName); - if (lang == null) - return null; - return lang.CreateCompletionBinding(expressionToComplete, fileName, location, context); + return SD.LanguageService.GetLanguageByExtension(".cs") + .CreateCompletionBinding(expressionToComplete, context); } } } diff --git a/src/Main/Base/Project/Src/Services/LanguageBinding/DefaultLanguageBinding.cs b/src/Main/Base/Project/Src/Services/LanguageBinding/DefaultLanguageBinding.cs index c1b1bf7216..f48211e1d1 100644 --- a/src/Main/Base/Project/Src/Services/LanguageBinding/DefaultLanguageBinding.cs +++ b/src/Main/Base/Project/Src/Services/LanguageBinding/DefaultLanguageBinding.cs @@ -75,7 +75,7 @@ namespace ICSharpCode.SharpDevelop } } - public virtual ICodeCompletionBinding CreateCompletionBinding(string expressionToComplete, FileName fileName, TextLocation location, ICodeContext context) + public virtual ICodeCompletionBinding CreateCompletionBinding(string expressionToComplete, ICodeContext context) { throw new NotSupportedException(); } diff --git a/src/Main/Base/Project/Src/Services/LanguageBinding/ILanguageBinding.cs b/src/Main/Base/Project/Src/Services/LanguageBinding/ILanguageBinding.cs index 49ad72abea..56528c08cc 100644 --- a/src/Main/Base/Project/Src/Services/LanguageBinding/ILanguageBinding.cs +++ b/src/Main/Base/Project/Src/Services/LanguageBinding/ILanguageBinding.cs @@ -65,6 +65,6 @@ namespace ICSharpCode.SharpDevelop /// /// Creates a completion binding for a given expression and context. /// - ICodeCompletionBinding CreateCompletionBinding(string expressionToComplete, FileName fileName, TextLocation location, ICodeContext context); + ICodeCompletionBinding CreateCompletionBinding(string expressionToComplete, ICodeContext context); } }