diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/Project/AspNet.Mvc.csproj b/src/AddIns/BackendBindings/AspNet.Mvc/Project/AspNet.Mvc.csproj
index 1f159d0b72..545ecdcfca 100644
--- a/src/AddIns/BackendBindings/AspNet.Mvc/Project/AspNet.Mvc.csproj
+++ b/src/AddIns/BackendBindings/AspNet.Mvc/Project/AspNet.Mvc.csproj
@@ -122,10 +122,13 @@
+
+
+
diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpDotCompletionDataProvider.cs b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpDotCompletionDataProvider.cs
index 0ed8a6889d..e2aba9cad3 100644
--- a/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpDotCompletionDataProvider.cs
+++ b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpDotCompletionDataProvider.cs
@@ -31,7 +31,7 @@ namespace ICSharpCode.AspNet.Mvc.Completion
ParseInformation CreateParseInformationWithWebViewPageClass(ParseInformation parseInfo)
{
- var compilationUnit = new DefaultCompilationUnit(parseInfo.CompilationUnit.ProjectContent);
+ RazorCompilationUnit compilationUnit = RazorCompilationUnit.CreateFromParseInfo(parseInfo);
AddDefaultUsings(compilationUnit);
AddWebViewPageClass(compilationUnit);
return new ParseInformation(compilationUnit);
@@ -58,34 +58,52 @@ namespace ICSharpCode.AspNet.Mvc.Completion
return defaultUsing;
}
- void AddWebViewPageClass(DefaultCompilationUnit compilationUnit)
+ void AddWebViewPageClass(RazorCompilationUnit compilationUnit)
{
DefaultClass webViewPageClass = CreateWebViewPageClass(compilationUnit);
compilationUnit.Classes.Add(webViewPageClass);
}
- DefaultClass CreateWebViewPageClass(ICompilationUnit compilationUnit)
+ DefaultClass CreateWebViewPageClass(RazorCompilationUnit compilationUnit)
{
var webViewPageClass = new DefaultClass(compilationUnit, "RazorWebViewPage") {
Region = new DomRegion(1, 0, 3, 0)
};
- AddWebViewPageBaseClass(webViewPageClass);
+ IReturnType modelType = GetModelReturnType(compilationUnit);
+ AddWebViewPageBaseClass(webViewPageClass, modelType);
return webViewPageClass;
}
- void AddWebViewPageBaseClass(DefaultClass webViewPageClass)
+ IReturnType GetModelReturnType(RazorCompilationUnit compilationUnit)
+ {
+ IClass modelType = GetClassIfTypeNameIsNotEmpty(compilationUnit.ProjectContent, compilationUnit.ModelTypeName);
+ if (modelType != null) {
+ return modelType.DefaultReturnType;
+ }
+ return new DynamicReturnType(compilationUnit.ProjectContent);
+ }
+
+ IClass GetClassIfTypeNameIsNotEmpty(IProjectContent projectContent, string modelTypeName)
+ {
+ if (!String.IsNullOrEmpty(modelTypeName)) {
+ return projectContent.GetClass(modelTypeName, 0);
+ }
+ return null;
+ }
+
+ void AddWebViewPageBaseClass(DefaultClass webViewPageClass, IReturnType modelType)
{
IClass webViewPageBaseClass = webViewPageClass.ProjectContent.GetClass("System.Web.Mvc.WebViewPage", 1);
if (webViewPageBaseClass != null) {
- IReturnType returnType = GetWebViewPageBaseClassReturnType(webViewPageBaseClass);
+ IReturnType returnType = GetWebViewPageBaseClassReturnType(webViewPageBaseClass, modelType);
webViewPageClass.BaseTypes.Add(returnType);
}
}
- IReturnType GetWebViewPageBaseClassReturnType(IClass webViewPageBaseClass)
+ IReturnType GetWebViewPageBaseClassReturnType(IClass webViewPageBaseClass, IReturnType modelType)
{
var typeArguments = new List();
- typeArguments.Add(new DynamicReturnType(webViewPageBaseClass.ProjectContent));
+ typeArguments.Add(modelType);
return new ConstructedReturnType(webViewPageBaseClass.DefaultReturnType, typeArguments);
}
diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpModelTypeLocater.cs b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpModelTypeLocater.cs
new file mode 100644
index 0000000000..36c72f8381
--- /dev/null
+++ b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpModelTypeLocater.cs
@@ -0,0 +1,34 @@
+// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
+// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
+
+using System;
+using System.Web.Razor;
+using ICSharpCode.SharpDevelop;
+
+namespace ICSharpCode.AspNet.Mvc.Completion
+{
+ public class RazorCSharpModelTypeLocater
+ {
+ public RazorCSharpModelTypeLocater(ITextBuffer textBuffer)
+ {
+ ParserResults results = ParseTemplate(textBuffer);
+ ModelTypeName = GetModelTypeName(results);
+ }
+
+ ParserResults ParseTemplate(ITextBuffer textBuffer)
+ {
+ var host = new RazorEngineHost(new CSharpRazorCodeLanguage());
+ var engine = new RazorTemplateEngine(host);
+ return engine.ParseTemplate(textBuffer.CreateReader());
+ }
+
+ string GetModelTypeName(ParserResults results)
+ {
+ var visitor = new RazorCSharpParserModelTypeVisitor();
+ results.Document.Accept(visitor);
+ return visitor.ModelTypeName;
+ }
+
+ public string ModelTypeName { get; private set; }
+ }
+}
diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpParser.cs b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpParser.cs
index b1a278c26d..1d8d7645eb 100644
--- a/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpParser.cs
+++ b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpParser.cs
@@ -39,7 +39,10 @@ namespace ICSharpCode.AspNet.Mvc.Completion
public ICompilationUnit Parse(IProjectContent projectContent, string fileName, ITextBuffer fileContent)
{
- return new DefaultCompilationUnit(projectContent);
+ var modelTypeLocater = new RazorCSharpModelTypeLocater(fileContent);
+ return new RazorCompilationUnit(projectContent) {
+ ModelTypeName = modelTypeLocater.ModelTypeName
+ };
}
public IResolver CreateResolver()
diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpParserModelTypeVisitor.cs b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpParserModelTypeVisitor.cs
new file mode 100644
index 0000000000..c1424045ca
--- /dev/null
+++ b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpParserModelTypeVisitor.cs
@@ -0,0 +1,59 @@
+// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
+// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
+
+using System;
+using System.Web.Razor.Parser;
+using System.Web.Razor.Parser.SyntaxTree;
+
+namespace ICSharpCode.AspNet.Mvc.Completion
+{
+ public class RazorCSharpParserModelTypeVisitor : ParserVisitor
+ {
+ bool foundModelTypeName;
+
+ public RazorCSharpParserModelTypeVisitor()
+ {
+ ModelTypeName = String.Empty;
+ }
+
+ public string ModelTypeName { get; private set; }
+
+ public override void VisitSpan(Span span)
+ {
+ Console.WriteLine("Span.Kind: " + span.Kind);
+ Console.WriteLine("Span.GetType(): " + span.GetType().Name);
+ Console.WriteLine("Span.Content: '" + span.Content + "'");
+
+ if (foundModelTypeName)
+ return;
+
+ if (IsModelSpan(span)) {
+ VisitModelNameSpan(span.Next);
+ }
+ }
+
+ bool IsModelSpan(Span span)
+ {
+ return span.Content == "model";
+ }
+
+ void VisitModelNameSpan(Span span)
+ {
+ if (span == null)
+ return;
+
+ string firstLineOfMarkup = GetFirstLine(span.Content);
+ ModelTypeName = firstLineOfMarkup.Trim();
+ foundModelTypeName = true;
+ }
+
+ string GetFirstLine(string text)
+ {
+ int endOfLineIndex = text.IndexOf('\r');
+ if (endOfLineIndex > 0) {
+ return text.Substring(0, endOfLineIndex);
+ }
+ return text;
+ }
+ }
+}
diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCompilationUnit.cs b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCompilationUnit.cs
new file mode 100644
index 0000000000..498c929da1
--- /dev/null
+++ b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCompilationUnit.cs
@@ -0,0 +1,34 @@
+// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
+// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
+
+using System;
+using ICSharpCode.SharpDevelop.Dom;
+
+namespace ICSharpCode.AspNet.Mvc.Completion
+{
+ public class RazorCompilationUnit : DefaultCompilationUnit
+ {
+ public RazorCompilationUnit(IProjectContent projectContent)
+ : base(projectContent)
+ {
+ }
+
+ public static RazorCompilationUnit CreateFromParseInfo(ParseInformation parseInformation)
+ {
+ return new RazorCompilationUnit(parseInformation.CompilationUnit.ProjectContent) {
+ ModelTypeName = GetModelTypeName(parseInformation.CompilationUnit)
+ };
+ }
+
+ static string GetModelTypeName(ICompilationUnit compilationUnit)
+ {
+ var originalRazorCompilationUnit = compilationUnit as RazorCompilationUnit;
+ if (originalRazorCompilationUnit != null) {
+ return originalRazorCompilationUnit.ModelTypeName;
+ }
+ return String.Empty;
+ }
+
+ public string ModelTypeName { get; set; }
+ }
+}
diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/Test/AspNet.Mvc.Tests.csproj b/src/AddIns/BackendBindings/AspNet.Mvc/Test/AspNet.Mvc.Tests.csproj
index e4487ba0af..f0bf407d37 100644
--- a/src/AddIns/BackendBindings/AspNet.Mvc/Test/AspNet.Mvc.Tests.csproj
+++ b/src/AddIns/BackendBindings/AspNet.Mvc/Test/AspNet.Mvc.Tests.csproj
@@ -117,6 +117,7 @@
+
@@ -189,6 +190,7 @@
+
\ No newline at end of file
diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/Test/Src/Completion/RazorCSharpParserTests.cs b/src/AddIns/BackendBindings/AspNet.Mvc/Test/Src/Completion/RazorCSharpParserTests.cs
new file mode 100644
index 0000000000..0ec664c234
--- /dev/null
+++ b/src/AddIns/BackendBindings/AspNet.Mvc/Test/Src/Completion/RazorCSharpParserTests.cs
@@ -0,0 +1,148 @@
+// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
+// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
+
+using System;
+using ICSharpCode.AspNet.Mvc.Completion;
+using ICSharpCode.SharpDevelop;
+using ICSharpCode.SharpDevelop.Dom;
+using NUnit.Framework;
+
+namespace AspNet.Mvc.Tests.Completion
+{
+ [TestFixture]
+ public class RazorCSharpParserTests
+ {
+ RazorCSharpParser parser;
+
+ void CreateParser()
+ {
+ parser = new RazorCSharpParser();
+ }
+
+ ICompilationUnit Parse(string code)
+ {
+ var projectContent = new DefaultProjectContent();
+ var textBuffer = new StringTextBuffer(code);
+ return parser.Parse(projectContent, @"d:\MyProject\Views\Index.cshtml", textBuffer);
+ }
+
+ [Test]
+ public void Parse_ModelDirectiveWithTypeName_ModelTypeNameFound()
+ {
+ CreateParser();
+ string code = "@model MvcApplication.MyModel\r\n";
+
+ var compilationUnit = Parse(code) as RazorCompilationUnit;
+
+ Assert.AreEqual("MvcApplication.MyModel", compilationUnit.ModelTypeName);
+ }
+
+ [Test]
+ public void Parse_ModelDirectiveWithTypeNameFollowedByHtmlMarkup_ModelTypeNameFound()
+ {
+ CreateParser();
+ string code =
+ "@model MvcApplication.LogonModel\r\n" +
+ "Index
\r\n";
+
+ var compilationUnit = Parse(code) as RazorCompilationUnit;
+
+ Assert.AreEqual("MvcApplication.LogonModel", compilationUnit.ModelTypeName);
+ }
+
+ [Test]
+ public void Parse_SingleLineFileWithModelDirectiveAndTypeNameButNoNewLineAtEnd_ModelTypeNameFound()
+ {
+ CreateParser();
+ string code = "@model MvcApplication.MyModel";
+
+ var compilationUnit = Parse(code) as RazorCompilationUnit;
+
+ Assert.AreEqual("MvcApplication.MyModel", compilationUnit.ModelTypeName);
+ }
+
+ [Test]
+ public void Parse_ModelTypeDirectiveWithTypeNameFollowedByRazorBlock_ModelTypeNameFound()
+ {
+ CreateParser();
+
+ string code =
+ "@model IEnumerable\r\n" +
+ "\r\n" +
+ "@{\r\n" +
+ " ViewBag.Title = \"Title1\";\r\n" +
+ "}\r\n" +
+ "\r\n";
+
+ var compilationUnit = Parse(code) as RazorCompilationUnit;
+
+ Assert.AreEqual("IEnumerable", compilationUnit.ModelTypeName);
+ }
+
+ [Test]
+ public void Parse_UsingDirective_ModelTypeNameIsEmptyString()
+ {
+ CreateParser();
+ string code = "@using System.Xml\r\n";
+
+ var compilationUnit = Parse(code) as RazorCompilationUnit;
+
+ Assert.AreEqual(String.Empty, compilationUnit.ModelTypeName);
+ }
+
+ [Test]
+ public void Parse_HelperDirective_ModelTypeNameIsEmptyString()
+ {
+ CreateParser();
+ string code = "@helper MyHelper\r\n";
+
+ var compilationUnit = Parse(code) as RazorCompilationUnit;
+
+ Assert.AreEqual(String.Empty, compilationUnit.ModelTypeName);
+ }
+
+ [Test]
+ public void Parse_HtmlMarkupOnly_ModelTypeNameIsEmptyString()
+ {
+ CreateParser();
+ string code = "heading
\r\n";
+
+ var compilationUnit = Parse(code) as RazorCompilationUnit;
+
+ Assert.AreEqual(String.Empty, compilationUnit.ModelTypeName);
+ }
+
+ [Test]
+ public void Parse_ModelDirectiveOnly_ModelTypeNameIsEmptyString()
+ {
+ CreateParser();
+ string code = "@model";
+
+ var compilationUnit = Parse(code) as RazorCompilationUnit;
+
+ Assert.AreEqual(String.Empty, compilationUnit.ModelTypeName);
+ }
+
+ [Test]
+ public void Parse_ModelStringInsideParagraphTags_ModelTypeNameIsEmptyString()
+ {
+ CreateParser();
+ string code = "model
";
+
+ var compilationUnit = Parse(code) as RazorCompilationUnit;
+
+ Assert.AreEqual(String.Empty, compilationUnit.ModelTypeName);
+ }
+
+ [Test]
+ public void Parse_ModelStringOnlyWithoutRazorTransition_ModelTypeNameIsEmptyString()
+ {
+ CreateParser();
+ string code = "model";
+
+ var compilationUnit = Parse(code) as RazorCompilationUnit;
+
+ Assert.AreEqual(String.Empty, compilationUnit.ModelTypeName);
+ }
+ }
+}