Browse Source

Add C# Razor completion for model.

Use the @model directive to generate a strongly typed WebViewPage class.
Support completion on the Model property in a view.
pull/28/head
Matt Ward 13 years ago
parent
commit
7a742d922f
  1. 3
      src/AddIns/BackendBindings/AspNet.Mvc/Project/AspNet.Mvc.csproj
  2. 34
      src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpDotCompletionDataProvider.cs
  3. 34
      src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpModelTypeLocater.cs
  4. 5
      src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpParser.cs
  5. 59
      src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpParserModelTypeVisitor.cs
  6. 34
      src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCompilationUnit.cs
  7. 2
      src/AddIns/BackendBindings/AspNet.Mvc/Test/AspNet.Mvc.Tests.csproj
  8. 148
      src/AddIns/BackendBindings/AspNet.Mvc/Test/Src/Completion/RazorCSharpParserTests.cs

3
src/AddIns/BackendBindings/AspNet.Mvc/Project/AspNet.Mvc.csproj

@ -122,10 +122,13 @@ @@ -122,10 +122,13 @@
<Compile Include="Src\AddMvcViewToProjectViewModel.cs" />
<Compile Include="Src\BooleanToVisibilityConverter.cs" />
<Compile Include="Src\CloseDialogBehaviour.cs" />
<Compile Include="Src\Completion\RazorCompilationUnit.cs" />
<Compile Include="Src\Completion\RazorCSharpCompletionBinding.cs" />
<Compile Include="Src\Completion\RazorCSharpDotCompletionDataProvider.cs" />
<Compile Include="Src\Completion\RazorCSharpExpressionFinder.cs" />
<Compile Include="Src\Completion\RazorCSharpModelTypeLocater.cs" />
<Compile Include="Src\Completion\RazorCSharpParser.cs" />
<Compile Include="Src\Completion\RazorCSharpParserModelTypeVisitor.cs" />
<Compile Include="Src\CurrentAppDomain.cs" />
<Compile Include="Src\CurrentAppDomainFactory.cs" />
<Compile Include="Src\DelegateCommand.cs" />

34
src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpDotCompletionDataProvider.cs

@ -31,7 +31,7 @@ namespace ICSharpCode.AspNet.Mvc.Completion @@ -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 @@ -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<IReturnType>();
typeArguments.Add(new DynamicReturnType(webViewPageBaseClass.ProjectContent));
typeArguments.Add(modelType);
return new ConstructedReturnType(webViewPageBaseClass.DefaultReturnType, typeArguments);
}

34
src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpModelTypeLocater.cs

@ -0,0 +1,34 @@ @@ -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; }
}
}

5
src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpParser.cs

@ -39,7 +39,10 @@ namespace ICSharpCode.AspNet.Mvc.Completion @@ -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()

59
src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpParserModelTypeVisitor.cs

@ -0,0 +1,59 @@ @@ -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;
}
}
}

34
src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCompilationUnit.cs

@ -0,0 +1,34 @@ @@ -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; }
}
}

2
src/AddIns/BackendBindings/AspNet.Mvc/Test/AspNet.Mvc.Tests.csproj

@ -117,6 +117,7 @@ @@ -117,6 +117,7 @@
<Compile Include="Src\CodeTemplates\RazorCSharpEditViewTemplateTests.cs" />
<Compile Include="Src\CodeTemplates\RazorCSharpEmptyViewTemplateTests.cs" />
<Compile Include="Src\CodeTemplates\RazorCSharpListViewTemplateTests.cs" />
<Compile Include="Src\Completion\RazorCSharpParserTests.cs" />
<Compile Include="Src\Folding\CharacterReaderTests.cs" />
<Compile Include="Src\Folding\HtmlReaderTests.cs" />
<Compile Include="Src\Folding\RazorHtmlFoldParserTests.cs" />
@ -189,6 +190,7 @@ @@ -189,6 +190,7 @@
<Folder Include="Src\CodeTemplates" />
<Folder Include="Src\CodeTemplates\Models" />
<Folder Include="Src\Folding" />
<Folder Include="Src\Completion" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
</Project>

148
src/AddIns/BackendBindings/AspNet.Mvc/Test/Src/Completion/RazorCSharpParserTests.cs

@ -0,0 +1,148 @@ @@ -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" +
"<h2>Index</h2>\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<MvcApplication1.Models.MyClass>\r\n" +
"\r\n" +
"@{\r\n" +
" ViewBag.Title = \"Title1\";\r\n" +
"}\r\n" +
"\r\n";
var compilationUnit = Parse(code) as RazorCompilationUnit;
Assert.AreEqual("IEnumerable<MvcApplication1.Models.MyClass>", 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 = "<h1>heading</h1>\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 = "<p>model</p>";
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);
}
}
}
Loading…
Cancel
Save