Initial prototype.
This commit is contained in:
Коммит
807fa56928
|
@ -0,0 +1,14 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = false
|
||||
|
||||
[*.{html,config,csproj}]
|
||||
indent_size = 2
|
||||
|
||||
[project.json]
|
||||
indent_size = 2
|
|
@ -0,0 +1,6 @@
|
|||
*.user
|
||||
project.lock.json
|
||||
.vs/
|
||||
**/wwwroot/external/
|
||||
bin/
|
||||
obj/
|
|
@ -0,0 +1,46 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.25420.1
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{ED635736-B827-4C88-80B9-EBBE1DDADF12}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F358FD73-4BC9-42AA-BC4B-38DDB81FE813}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
global.json = global.json
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "MirrorSharp", "src\MirrorSharp\MirrorSharp.xproj", "{C130C962-D17F-4741-B2B4-D74263BF380A}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "MirrorSharp.Demo", "src\MirrorSharp.Demo\MirrorSharp.Demo.xproj", "{70BCCC0E-6EEF-40D0-932A-87F9C42BD67B}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "MirrorSharp.Tests", "src\MirrorSharp.Tests\MirrorSharp.Tests.xproj", "{09F91A91-3DB9-44FF-A65E-5DB5A3F3A7A5}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{C130C962-D17F-4741-B2B4-D74263BF380A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C130C962-D17F-4741-B2B4-D74263BF380A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C130C962-D17F-4741-B2B4-D74263BF380A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C130C962-D17F-4741-B2B4-D74263BF380A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{70BCCC0E-6EEF-40D0-932A-87F9C42BD67B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{70BCCC0E-6EEF-40D0-932A-87F9C42BD67B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{70BCCC0E-6EEF-40D0-932A-87F9C42BD67B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{70BCCC0E-6EEF-40D0-932A-87F9C42BD67B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{09F91A91-3DB9-44FF-A65E-5DB5A3F3A7A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{09F91A91-3DB9-44FF-A65E-5DB5A3F3A7A5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{09F91A91-3DB9-44FF-A65E-5DB5A3F3A7A5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{09F91A91-3DB9-44FF-A65E-5DB5A3F3A7A5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{C130C962-D17F-4741-B2B4-D74263BF380A} = {ED635736-B827-4C88-80B9-EBBE1DDADF12}
|
||||
{70BCCC0E-6EEF-40D0-932A-87F9C42BD67B} = {ED635736-B827-4C88-80B9-EBBE1DDADF12}
|
||||
{09F91A91-3DB9-44FF-A65E-5DB5A3F3A7A5} = {ED635736-B827-4C88-80B9-EBBE1DDADF12}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -0,0 +1,12 @@
|
|||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ACCESSOR_DECLARATION_BRACES/@EntryValue">END_OF_LINE</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ACCESSOR_OWNER_DECLARATION_BRACES/@EntryValue">END_OF_LINE</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ANONYMOUS_METHOD_DECLARATION_BRACES/@EntryValue">END_OF_LINE</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/CASE_BLOCK_BRACES/@EntryValue">END_OF_LINE</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INITIALIZER_BRACES/@EntryValue">END_OF_LINE</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INVOCABLE_DECLARATION_BRACES/@EntryValue">END_OF_LINE</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/OTHER_BRACES/@EntryValue">END_OF_LINE</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/TYPE_DECLARATION_BRACES/@EntryValue">END_OF_LINE</s:String>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAddAccessorOwnerDeclarationBracesMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"projects": [ "src", "test" ],
|
||||
"sdk": {
|
||||
"version": "1.0.0-preview2-003121"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"directory": "wwwroot/external"
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>70bccc0e-6eef-40d0-932a-87f9c42bd67b</ProjectGuid>
|
||||
<RootNamespace>MirrorSharp.Demo</RootNamespace>
|
||||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
|
||||
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<DnxInvisibleContent Include="bower.json" />
|
||||
<DnxInvisibleContent Include=".bowerrc" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VSToolsPath)\DotNet.Web\Microsoft.DotNet.Web.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
|
@ -0,0 +1,24 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
|
||||
namespace MirrorSharp.Demo
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var host = new WebHostBuilder()
|
||||
.UseKestrel()
|
||||
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||
.UseIISIntegration()
|
||||
.UseStartup<Startup>()
|
||||
.Build();
|
||||
|
||||
host.Run();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,187 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Welcome to ASP.NET Core</title>
|
||||
<style>
|
||||
html {
|
||||
background: #f1f1f1;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
background: #fff;
|
||||
color: #505050;
|
||||
font: 14px 'Segoe UI', tahoma, arial, helvetica, sans-serif;
|
||||
margin: 1%;
|
||||
min-height: 95.5%;
|
||||
border: 1px solid silver;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#header {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#header h1 {
|
||||
font-size: 44px;
|
||||
font-weight: normal;
|
||||
margin: 0;
|
||||
padding: 10px 30px 10px 30px;
|
||||
}
|
||||
|
||||
#header span {
|
||||
margin: 0;
|
||||
padding: 0 30px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#header p {
|
||||
font-size: 20px;
|
||||
color: #fff;
|
||||
background: #007acc;
|
||||
padding: 0 30px;
|
||||
line-height: 50px;
|
||||
margin-top: 25px;
|
||||
|
||||
}
|
||||
|
||||
#header p a {
|
||||
color: #fff;
|
||||
text-decoration: underline;
|
||||
font-weight: bold;
|
||||
padding-right: 35px;
|
||||
background: no-repeat right bottom url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABcAAAAWCAMAAAAcqPc3AAAANlBMVEUAAAAAeswfitI9mthXp91us+KCvuaTx+mjz+2x1u+83PLH4vTR5/ba7Pjj8Pns9fv1+v3////wy3dWAAAAAXRSTlMAQObYZgAAAHxJREFUeNp9kVcSwCAIRMHUYoH7XzaxOxJ9P8oyQ1uIqNPwh3s2aLmIM2YtqrLcQIeQEylhuCeUOlhgve5yoBCfWmlnlgkN4H8ykbpaE7gR03AbUHiwoOxUH9Xp+ubd41p1HF3mBPrfC87BHeTdaB3ceeKL9HGpcvX9zu6+DdMWT9KQPvYAAAAASUVORK5CYII=);
|
||||
}
|
||||
|
||||
#main {
|
||||
padding: 5px 30px;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.section {
|
||||
width: 21.7%;
|
||||
float: left;
|
||||
margin: 0 0 0 4%;
|
||||
}
|
||||
|
||||
.section h2 {
|
||||
font-size: 13px;
|
||||
text-transform: uppercase;
|
||||
margin: 0;
|
||||
border-bottom: 1px solid silver;
|
||||
padding-bottom: 12px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.section.first {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.section.first h2 {
|
||||
font-size: 24px;
|
||||
text-transform: none;
|
||||
margin-bottom: 25px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.section.first li {
|
||||
border-top: 1px solid silver;
|
||||
padding: 8px 0;
|
||||
}
|
||||
|
||||
.section.last {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
li {
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #267cb2;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
#footer {
|
||||
clear: both;
|
||||
padding-top: 50px;
|
||||
}
|
||||
|
||||
#footer p {
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="header">
|
||||
<h1>Welcome to ASP.NET Core</h1>
|
||||
<span>
|
||||
We've made some big updates in this release, so it’s <b>important</b> that you spend
|
||||
a few minutes to learn what’s new.
|
||||
</span>
|
||||
<p>You've created a new ASP.NET Core project. <a href="http://go.microsoft.com/fwlink/?LinkId=518016">Learn what's new</a></p>
|
||||
</div>
|
||||
|
||||
<div id="main">
|
||||
<div class="section first">
|
||||
<h2>This application consists of:</h2>
|
||||
<ul>
|
||||
<li>Sample pages using ASP.NET Core MVC</li>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkId=518004">Bower</a> for managing client-side libraries</li>
|
||||
<li>Theming using <a href="http://go.microsoft.com/fwlink/?LinkID=398939">Bootstrap</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section">
|
||||
<h2>How to</h2>
|
||||
<ul>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkID=398600">Add a Controller and View</a></li>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkID=699562">Add an appsetting in config and access it in app.</a></li>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkId=699315">Manage User Secrets using Secret Manager.</a></li>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkId=699316">Use logging to log a message.</a></li>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkId=699317">Add packages using NuGet.</a></li>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkId=699318">Add client packages using Bower.</a></li>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkId=699319">Target development, staging or production environment.</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section">
|
||||
<h2>Overview</h2>
|
||||
<ul>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkId=518008">Conceptual overview of what is ASP.NET Core</a></li>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkId=699320">Fundamentals of ASP.NET Core such as Startup and middleware.</a></li>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkId=398602">Working with Data</a></li>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkId=398603">Security</a></li>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkID=699321">Client side development</a></li>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkID=699322">Develop on different platforms</a></li>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkID=699323">Read more on the documentation site</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section last">
|
||||
<h2>Run & Deploy</h2>
|
||||
<ul>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkID=517851">Run your app</a></li>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkID=517853">Run tools such as EF migrations and more</a></li>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkID=398609">Publish to Microsoft Azure Web Apps</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div id="footer">
|
||||
<p>We would love to hear your <a href="http://go.microsoft.com/fwlink/?LinkId=518015">feedback</a></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:57835/",
|
||||
"sslPort": 0
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"MirrorSharp.Demo": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "http://localhost:5000",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace MirrorSharp.Demo {
|
||||
public class Startup {
|
||||
// This method gets called by the runtime. Use this method to add services to the container.
|
||||
// For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940
|
||||
public void ConfigureServices(IServiceCollection services) {
|
||||
}
|
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) {
|
||||
loggerFactory.AddConsole();
|
||||
if (env.IsDevelopment())
|
||||
app.UseDeveloperExceptionPage();
|
||||
|
||||
app.UseDefaultFiles()
|
||||
.UseStaticFiles()
|
||||
.UseWebSockets()
|
||||
.UseMirrorSharp();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"name": "mirrorsharp-demo",
|
||||
"authors": [
|
||||
"Andrey Shchekin <ashmind@gmail.com>"
|
||||
],
|
||||
"description": "",
|
||||
"main": "",
|
||||
"license": "MIT",
|
||||
"homepage": "",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"codemirror": "^5.18.2"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.App": {
|
||||
"version": "1.0.0",
|
||||
"type": "platform"
|
||||
},
|
||||
"Microsoft.AspNetCore.Diagnostics": "1.0.0",
|
||||
"Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
|
||||
"Microsoft.AspNetCore.Server.Kestrel": "1.0.0",
|
||||
"Microsoft.Extensions.Logging.Console": "1.0.0",
|
||||
"MirrorSharp": "*",
|
||||
"Microsoft.AspNetCore.StaticFiles": "1.0.0",
|
||||
"Microsoft.AspNetCore.WebSockets.Server": "0.1.0"
|
||||
},
|
||||
|
||||
"tools": {
|
||||
"Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final"
|
||||
},
|
||||
|
||||
"frameworks": {
|
||||
"netcoreapp1.0": {
|
||||
"imports": [
|
||||
"dotnet5.6",
|
||||
"portable-net45+win8"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
"buildOptions": {
|
||||
"emitEntryPoint": true,
|
||||
"preserveCompilationContext": true
|
||||
},
|
||||
|
||||
"runtimeOptions": {
|
||||
"configProperties": {
|
||||
"System.GC.Server": true
|
||||
}
|
||||
},
|
||||
|
||||
"publishOptions": {
|
||||
"include": [
|
||||
"wwwroot",
|
||||
"web.config"
|
||||
]
|
||||
},
|
||||
|
||||
"scripts": {
|
||||
"postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
|
||||
<!--
|
||||
Configure your application settings in appsettings.json. Learn more at http://go.microsoft.com/fwlink/?LinkId=786380
|
||||
-->
|
||||
|
||||
<system.webServer>
|
||||
<handlers>
|
||||
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified"/>
|
||||
</handlers>
|
||||
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false"/>
|
||||
</system.webServer>
|
||||
</configuration>
|
|
@ -0,0 +1,23 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>MirrorSharp Demo</title>
|
||||
<link rel="stylesheet" href="external/codemirror/lib/codemirror.css" />
|
||||
<link rel="stylesheet" href="external/codemirror/addon/lint/lint.css" />
|
||||
<link rel="stylesheet" href="external/codemirror/addon/hint/show-hint.css" />
|
||||
</head>
|
||||
<body>
|
||||
<textarea></textarea>
|
||||
|
||||
<script src="external/codemirror/lib/codemirror.js"></script>
|
||||
<script src="external/codemirror/addon/lint/lint.js"></script>
|
||||
<script src="external/codemirror/addon/hint/show-hint.js"></script>
|
||||
<script src="js/mirrorsharp.js"></script>
|
||||
<script type="text/javascript">
|
||||
mirrorsharp(document.getElementsByTagName('textarea')[0], {
|
||||
serviceUrl: window.location.href.replace(/^http(.+)\/?$/i, 'ws$1/mirrorsharp')
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,77 @@
|
|||
(function (root, factory) {
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
define(['CodeMirror'], factory);
|
||||
} else if (typeof module === 'object' && module.exports) {
|
||||
module.exports = factory(require('CodeMirror'));
|
||||
} else {
|
||||
root.mirrorsharp = factory(root.CodeMirror);
|
||||
}
|
||||
}(this, function (CodeMirror) {
|
||||
function getCursorIndex(cm) {
|
||||
return cm.indexFromPos(cm.getCursor());
|
||||
}
|
||||
|
||||
function showCompletions(cm, completions) {
|
||||
cm.showHint({
|
||||
hint: function () {
|
||||
return { list: completions };
|
||||
},
|
||||
completeSingle: false
|
||||
});
|
||||
}
|
||||
|
||||
return function(textarea, options) {
|
||||
const socket = new WebSocket(options.serviceUrl);
|
||||
|
||||
const cmOptions = options.forCodeMirror || { gutters: [] };
|
||||
//cmOptions.lint = { async: true, getAnnotations: lint };
|
||||
cmOptions.gutters.push('CodeMirror-lint-markers');
|
||||
|
||||
const cm = CodeMirror.fromTextArea(textarea, cmOptions);
|
||||
const indexKey = '$$mirrorsharp_index$$';
|
||||
|
||||
var changePending = false;
|
||||
cm.on('beforeChange', function(s, change) {
|
||||
change.from[indexKey] = cm.indexFromPos(change.from);
|
||||
change.to[indexKey] = cm.indexFromPos(change.to);
|
||||
changePending = true;
|
||||
});
|
||||
|
||||
cm.on('cursorActivity', function() {
|
||||
if (changePending)
|
||||
return;
|
||||
const cursorIndex = getCursorIndex(cm);
|
||||
socket.send('C' + cursorIndex);
|
||||
});
|
||||
|
||||
cm.on('changes', function(s, changes) {
|
||||
const cursorIndex = getCursorIndex(cm);
|
||||
changePending = false;
|
||||
for (var change of changes) {
|
||||
const start = change.from[indexKey];
|
||||
const length = change.to[indexKey] - start;
|
||||
const text = change.text;
|
||||
var message;
|
||||
if (cursorIndex === start + 1 && text.length === 1) {
|
||||
// typed a character
|
||||
message = 'T' + text;
|
||||
}
|
||||
else {
|
||||
// everything else
|
||||
message = 'R' + start + ':' + length + ':' + cursorIndex + ':' + text;
|
||||
}
|
||||
|
||||
socket.send(message);
|
||||
}
|
||||
});
|
||||
|
||||
socket.addEventListener('message', function (e) {
|
||||
const message = JSON.parse(e.data);
|
||||
switch (message.type) {
|
||||
case 'completions':
|
||||
showCompletions(cm, message.completions);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
}));
|
|
@ -0,0 +1,63 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.WebSockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MirrorSharp.Internal;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace MirrorSharp.Tests {
|
||||
public class ConnectionTests {
|
||||
[Theory]
|
||||
[InlineData("C1", 1)]
|
||||
[InlineData("C79", 79)]
|
||||
[InlineData("C1234567890", 1234567890)]
|
||||
public async void ReceiveAndProcessAsync_CallsMoveCursorOnSession_AfterReceivingMoveCursorCommand(string command, int expectedPosition) {
|
||||
var socketMock = Mock.Of<WebSocket>();
|
||||
SetupReceive(socketMock, command);
|
||||
var sessionMock = Mock.Of<IWorkSession>();
|
||||
|
||||
await new Connection(socketMock, sessionMock).ReceiveAndProcessAsync();
|
||||
Mock.Get(sessionMock).Verify(s => s.MoveCursor(expectedPosition));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("T1", '1')]
|
||||
[InlineData("Ta", 'a')]
|
||||
[InlineData("T\u0216", '\u0216')]
|
||||
[InlineData("T月", '月')]
|
||||
public async void ReceiveAndProcessAsync_CallsTypeCharAsyncOnSession_AfterReceivingTypeCharCommand(string command, char expectedChar) {
|
||||
var socketMock = Mock.Of<WebSocket>();
|
||||
SetupReceive(socketMock, command);
|
||||
var sessionMock = Mock.Of<IWorkSession>();
|
||||
|
||||
await new Connection(socketMock, sessionMock).ReceiveAndProcessAsync();
|
||||
Mock.Get(sessionMock).Verify(s => s.TypeCharAsync(expectedChar));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("R1:10:1:text", 1, 10, 1, "text")]
|
||||
[InlineData("R1:10:1:", 1, 10, 1, "")]
|
||||
[InlineData("R1:1:1:t:e:xt", 1, 1, 1, "t:e:xt")]
|
||||
public async void ReceiveAndProcessAsync_CallsReplaceTextOnSession_AfterReceivingReplaceCommand(string command, int expectedStart, int expectedLength, int expectedPosition, string expectedText) {
|
||||
var socketMock = Mock.Of<WebSocket>();
|
||||
SetupReceive(socketMock, command);
|
||||
var sessionMock = Mock.Of<IWorkSession>();
|
||||
|
||||
await new Connection(socketMock, sessionMock).ReceiveAndProcessAsync();
|
||||
Mock.Get(sessionMock).Verify(s => s.ReplaceText(expectedStart, expectedLength, expectedText, expectedPosition));
|
||||
}
|
||||
|
||||
private static void SetupReceive(WebSocket socket, string command) {
|
||||
Mock.Get(socket)
|
||||
.Setup(m => m.ReceiveAsync(It.IsAny<ArraySegment<byte>>(), It.IsAny<CancellationToken>()))
|
||||
.Returns((ArraySegment<byte> s, CancellationToken _) => {
|
||||
var byteCount = Encoding.UTF8.GetBytes(command.ToCharArray(), 0, command.Length, s.Array, s.Offset);
|
||||
return Task.FromResult(new WebSocketReceiveResult(byteCount, WebSocketMessageType.Text, true));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>09f91a91-3db9-44ff-a65e-5db5a3f3a7a5</ProjectGuid>
|
||||
<RootNamespace>MirrorSharp.Tests</RootNamespace>
|
||||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
|
||||
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
|
@ -0,0 +1,19 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("MirrorSharp.Tests")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("09f91a91-3db9-44ff-a65e-5db5a3f3a7a5")]
|
|
@ -0,0 +1,34 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using MirrorSharp.Internal;
|
||||
using Xunit;
|
||||
|
||||
namespace MirrorSharp.Tests {
|
||||
public class SessionTests {
|
||||
[Fact]
|
||||
public async Task TypeChar_ProducesExpectedCompletion() {
|
||||
var session = SessionFromTextWithCursor(@"
|
||||
class A { public int x; }
|
||||
class B { void M(A a) { a| } }
|
||||
");
|
||||
|
||||
var result = await session.TypeCharAsync('.');
|
||||
|
||||
Assert.Equal(
|
||||
new[] { "x" },
|
||||
result.Completions.Items.Select(i => i.DisplayText)
|
||||
);
|
||||
}
|
||||
|
||||
private WorkSession SessionFromTextWithCursor(string textWithCursor) {
|
||||
var cursorPosition = textWithCursor.LastIndexOf('|');
|
||||
var text = textWithCursor.Remove(cursorPosition, 1);
|
||||
|
||||
var session = new WorkSession();
|
||||
session.ReplaceText(0, 0, text, cursorPosition);
|
||||
return session;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"version": "1.0.0-*",
|
||||
"testRunner": "xunit",
|
||||
|
||||
"dependencies": {
|
||||
"NETStandard.Library": "1.6.0",
|
||||
"xunit": "2.2.0-beta2-build3300",
|
||||
"dotnet-test-xunit": "2.2.0-preview2-build1029",
|
||||
"Moq": "4.6.38-alpha",
|
||||
"MirrorSharp": "*"
|
||||
},
|
||||
|
||||
"frameworks": {
|
||||
"netcoreapp1.0": {
|
||||
"imports": [ "dnxcore50", "portable-net45+win8+wp8+wpa81", "portable-net45+win8" ],
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.App": {
|
||||
"type": "platform",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using MirrorSharp.Internal;
|
||||
|
||||
namespace MirrorSharp {
|
||||
public static class AppBuilderExtensions {
|
||||
public static void UseMirrorSharp(this IApplicationBuilder app) {
|
||||
app.UseMiddleware<Middleware>();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.WebSockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace MirrorSharp.Internal {
|
||||
public class Connection : IAsyncDisposable {
|
||||
private static class Commands {
|
||||
public const byte MoveCursor = (byte)'C';
|
||||
public const byte Replace = (byte)'R';
|
||||
public const byte TypeChar = (byte)'T';
|
||||
}
|
||||
|
||||
private readonly WebSocket _socket;
|
||||
private readonly IWorkSession _session;
|
||||
private readonly byte[] _inputByteBuffer = new byte[2048];
|
||||
private readonly byte[] _outputByteBuffer = new byte[2048];
|
||||
private readonly char[] _charBuffer = new char[2048];
|
||||
|
||||
private readonly JsonSerializer _jsonSerializer = new JsonSerializer();
|
||||
private readonly MemoryStream _jsonOutputStream;
|
||||
private readonly JsonWriter _jsonOutputWriter;
|
||||
|
||||
public Connection(WebSocket socket, IWorkSession session) {
|
||||
_socket = socket;
|
||||
_session = session;
|
||||
_jsonOutputStream = new MemoryStream(_outputByteBuffer);
|
||||
_jsonOutputWriter = new JsonTextWriter(new StreamWriter(_jsonOutputStream));
|
||||
}
|
||||
|
||||
public bool IsConnected => _socket.State == WebSocketState.Open;
|
||||
|
||||
public async Task ReceiveAndProcessAsync() {
|
||||
try {
|
||||
await ReceiveAndProcessInternalAsync().ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
try {
|
||||
await SendTextAsync("RM-ERR-??: " + ex.Message).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception sendException) {
|
||||
throw new AggregateException(ex, sendException);
|
||||
}
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ReceiveAndProcessInternalAsync() {
|
||||
var received = await _socket.ReceiveAsync(new ArraySegment<byte>(_inputByteBuffer), CancellationToken.None).ConfigureAwait(false);
|
||||
if (received.MessageType == WebSocketMessageType.Binary)
|
||||
throw new FormatException("Expected text data (received binary).");
|
||||
|
||||
if (received.MessageType == WebSocketMessageType.Close)
|
||||
return;
|
||||
|
||||
await ProcessMessageAsync(new ArraySegment<byte>(_inputByteBuffer, 0, received.Count)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private Task ProcessMessageAsync(ArraySegment<byte> data) {
|
||||
var command = data.Array[data.Offset];
|
||||
switch (command) {
|
||||
case Commands.Replace: {
|
||||
ProcessReplace(Shift(data));
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
case Commands.MoveCursor: {
|
||||
ProcessMoveCursor(Shift(data));
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
case Commands.TypeChar: return ProcessTypeCharAsync(Shift(data));
|
||||
default: throw new FormatException($"Unknown command: '{(char)command}'.");
|
||||
}
|
||||
}
|
||||
|
||||
private ArraySegment<byte> Shift(ArraySegment<byte> data) {
|
||||
return new ArraySegment<byte>(data.Array, data.Offset + 1, data.Count - 1);
|
||||
}
|
||||
|
||||
private void ProcessReplace(ArraySegment<byte> data) {
|
||||
var endOffset = data.Offset + data.Count - 1;
|
||||
var partStart = data.Offset;
|
||||
int? start = null;
|
||||
int? length = null;
|
||||
int? cursorPosition = null;
|
||||
|
||||
for (var i = data.Offset; i <= endOffset; i++) {
|
||||
if (data.Array[i] != (byte)':')
|
||||
continue;
|
||||
|
||||
var part = new ArraySegment<byte>(data.Array, partStart, i - partStart);
|
||||
if (start == null) {
|
||||
start = FastConvert.Utf8ByteArrayToInt32(part);
|
||||
partStart = i + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (length == null) {
|
||||
length = FastConvert.Utf8ByteArrayToInt32(part);
|
||||
partStart = i + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
cursorPosition = FastConvert.Utf8ByteArrayToInt32(part);
|
||||
partStart = i + 1;
|
||||
break;
|
||||
}
|
||||
if (start == null || length == null || cursorPosition == null)
|
||||
throw new Exception("Command 'R' must be in a format 'Rstart:length:cursor:text'.");
|
||||
|
||||
var text = Encoding.UTF8.GetString(data.Array, partStart, endOffset - partStart + 1);
|
||||
_session.ReplaceText(start.Value, length.Value, text, cursorPosition.Value);
|
||||
}
|
||||
|
||||
private void ProcessMoveCursor(ArraySegment<byte> data) {
|
||||
var cursorPosition = FastConvert.Utf8ByteArrayToInt32(data);
|
||||
_session.MoveCursor(cursorPosition);
|
||||
}
|
||||
|
||||
private async Task ProcessTypeCharAsync(ArraySegment<byte> data) {
|
||||
var @char = FastConvert.Utf8ByteArrayToChar(data, _charBuffer);
|
||||
|
||||
var result = await _session.TypeCharAsync(@char).ConfigureAwait(false);
|
||||
if (result.Completions == null)
|
||||
return;
|
||||
|
||||
await SendJsonAsync(new {
|
||||
type = "completions",
|
||||
completions = result.Completions.Items.Select(i => $"[{string.Join(",", i.Tags)}] {i.DisplayText}")
|
||||
}).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private Task SendJsonAsync(object value) {
|
||||
_jsonOutputStream.Seek(0, SeekOrigin.Begin);
|
||||
_jsonSerializer.Serialize(_jsonOutputWriter, value);
|
||||
_jsonOutputWriter.Flush();
|
||||
return SendOutputBufferAsync((int)_jsonOutputStream.Position);
|
||||
}
|
||||
|
||||
private Task SendTextAsync(string text) {
|
||||
var byteCount = Encoding.UTF8.GetBytes(text, 0, text.Length, _outputByteBuffer, 0);
|
||||
return SendOutputBufferAsync(byteCount);
|
||||
}
|
||||
|
||||
private Task SendOutputBufferAsync(int byteCount) {
|
||||
return _socket.SendAsync(new ArraySegment<byte>(_outputByteBuffer, 0, byteCount), WebSocketMessageType.Text, true, CancellationToken.None);
|
||||
}
|
||||
|
||||
public Task DisposeAsync() => _session.DisposeAsync();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace MirrorSharp.Internal {
|
||||
internal static class FastConvert {
|
||||
private const byte Utf8Zero = (byte)'0';
|
||||
private const byte Utf8Nine = (byte)'9';
|
||||
|
||||
private static readonly string[] CharStringMap =
|
||||
Enumerable.Range(0, 128).Select(c => ((char)c).ToString()).ToArray();
|
||||
|
||||
public static int Utf8ByteArrayToInt32(ArraySegment<byte> bytes) {
|
||||
var result = 0;
|
||||
var array = bytes.Array;
|
||||
var count = bytes.Offset + bytes.Count;
|
||||
for (var i = bytes.Offset; i < count; i++) {
|
||||
var @byte = array[i];
|
||||
if (@byte < Utf8Zero || @byte > Utf8Nine)
|
||||
throw new FormatException($"String '{SlowUtf8ByteArrayToString(bytes)}' is not a valid positive number.");
|
||||
|
||||
result = (10 * result) + (@byte - Utf8Zero);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static char Utf8ByteArrayToChar(ArraySegment<byte> bytes, char[] buffer) {
|
||||
if (bytes.Count == 1)
|
||||
return (char)bytes.Array[bytes.Offset];
|
||||
|
||||
var charCount = Encoding.UTF8.GetChars(bytes.Array, bytes.Offset, bytes.Count, buffer, 0);
|
||||
if (charCount != 1)
|
||||
throw new FormatException($"Expected one char, but conversion produced {charCount}.");
|
||||
|
||||
return buffer[0];
|
||||
}
|
||||
|
||||
public static string CharToString(char c) {
|
||||
if (c <= 127)
|
||||
return CharStringMap[c];
|
||||
|
||||
return c.ToString();
|
||||
}
|
||||
|
||||
private static string SlowUtf8ByteArrayToString(ArraySegment<byte> bytes) {
|
||||
return Encoding.UTF8.GetString(bytes.Array, bytes.Offset, bytes.Count);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
using System.Threading.Tasks;
|
||||
|
||||
namespace MirrorSharp.Internal {
|
||||
public interface IAsyncDisposable {
|
||||
Task DisposeAsync();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
using System.Threading.Tasks;
|
||||
|
||||
namespace MirrorSharp.Internal {
|
||||
public interface IWorkSession : IAsyncDisposable {
|
||||
void ReplaceText(int start, int length, string newText, int cursorPositionAfter);
|
||||
void MoveCursor(int cursorPosition);
|
||||
Task<TypeCharResult> TypeCharAsync(char @char);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
using System;
|
||||
using System.Net.WebSockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace MirrorSharp.Internal {
|
||||
public class Middleware {
|
||||
private readonly RequestDelegate _next;
|
||||
|
||||
public Middleware(RequestDelegate next) {
|
||||
_next = next;
|
||||
}
|
||||
|
||||
[UsedImplicitly]
|
||||
public async Task Invoke(HttpContext context) {
|
||||
if (!context.WebSockets.IsWebSocketRequest) {
|
||||
await _next(context);
|
||||
return;
|
||||
}
|
||||
|
||||
using (var socket = await context.WebSockets.AcceptWebSocketAsync().ConfigureAwait(false)) {
|
||||
var output = new byte[2048];
|
||||
|
||||
WorkSession session = null;
|
||||
Connection connection = null;
|
||||
try {
|
||||
session = new WorkSession();
|
||||
connection = new Connection(socket, session);
|
||||
|
||||
while (connection.IsConnected) {
|
||||
try {
|
||||
await connection.ReceiveAndProcessAsync();
|
||||
}
|
||||
catch {
|
||||
// this is sent back by connection itself
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception) when(connection == null && session != null) {
|
||||
await session.DisposeAsync().ConfigureAwait(false);
|
||||
throw;
|
||||
}
|
||||
finally {
|
||||
if (connection != null)
|
||||
await connection.DisposeAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.CodeAnalysis.Completion;
|
||||
|
||||
namespace MirrorSharp.Internal {
|
||||
public struct TypeCharResult {
|
||||
public TypeCharResult([CanBeNull] CompletionList completions) {
|
||||
Completions = completions;
|
||||
}
|
||||
|
||||
[CanBeNull] public CompletionList Completions { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
using System;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.Completion;
|
||||
using Microsoft.CodeAnalysis.Host.Mef;
|
||||
using Microsoft.CodeAnalysis.Text;
|
||||
|
||||
namespace MirrorSharp.Internal {
|
||||
public class WorkSession : IWorkSession {
|
||||
|
||||
private static readonly MefHostServices HostServices = MefHostServices.Create(MefHostServices.DefaultAssemblies.AddRange(new[] {
|
||||
Assembly.Load(new AssemblyName("Microsoft.CodeAnalysis.Features")),
|
||||
Assembly.Load(new AssemblyName("Microsoft.CodeAnalysis.CSharp.Features"))
|
||||
}));
|
||||
|
||||
private readonly AdhocWorkspace _workspace;
|
||||
|
||||
private readonly TextChange[] _oneTextChange = new TextChange[1];
|
||||
private Document _document;
|
||||
private SourceText _text;
|
||||
private int _cursorPosition;
|
||||
|
||||
private readonly CompletionService _completionService;
|
||||
|
||||
//private readonly Task _compilationLoopTask;
|
||||
private readonly CancellationTokenSource _disposing;
|
||||
|
||||
public WorkSession() {
|
||||
_disposing = new CancellationTokenSource();
|
||||
//_compilationLoopTask = Task.Run(CompilationLoop);
|
||||
|
||||
_workspace = new AdhocWorkspace(HostServices);
|
||||
|
||||
var project = _workspace.AddProject("_", "C#");
|
||||
_text = SourceText.From("");
|
||||
_document = project.AddDocument("_", _text);
|
||||
|
||||
_completionService = CompletionService.GetService(_document);
|
||||
if (_completionService == null)
|
||||
throw new Exception("Failed to retrieve the completion service.");
|
||||
}
|
||||
|
||||
public void ReplaceText(int start, int length, string newText, int cursorPositionAfter) {
|
||||
_oneTextChange[0] = new TextChange(new TextSpan(start, length), newText);
|
||||
_text = _text.WithChanges(_oneTextChange);
|
||||
_document = _document.WithText(_text);
|
||||
_cursorPosition = cursorPositionAfter;
|
||||
}
|
||||
|
||||
public void ReplaceAllText(string newText) {
|
||||
_text = SourceText.From(newText);
|
||||
_document = _document.WithText(_text);
|
||||
_cursorPosition = 0;
|
||||
}
|
||||
|
||||
public void MoveCursor(int cursorPosition) {
|
||||
_cursorPosition = cursorPosition;
|
||||
}
|
||||
|
||||
public async Task<TypeCharResult> TypeCharAsync(char @char) {
|
||||
ReplaceText(_cursorPosition, 1, FastConvert.CharToString(@char), _cursorPosition + 1);
|
||||
var completions = await _completionService.GetCompletionsAsync(_document, _cursorPosition).ConfigureAwait(false);
|
||||
return new TypeCharResult(completions);
|
||||
}
|
||||
|
||||
/*private async Task CompilationLoop() {
|
||||
var lastText = _text;
|
||||
var lastCompilation = CSharpCompilation.Create("_", new[] {_document.GetSyntaxTreeAsync() });
|
||||
|
||||
while (!_disposing.IsCancellationRequested) {
|
||||
if (_text != lastText) {
|
||||
_completionService.ShouldTriggerCompletion()
|
||||
|
||||
var compilation = lastCompilation.ReplaceSyntaxTree(lastTree, tree);
|
||||
_callback(compilation.GetDiagnostics().Select(d => d.GetMessage()).ToArray());
|
||||
lastText = _text;
|
||||
lastCompilation = compilation;
|
||||
}
|
||||
|
||||
try {
|
||||
await Task.Delay(500, _disposing.Token).ConfigureAwait(false);
|
||||
}
|
||||
catch (OperationCanceledException) {}
|
||||
}
|
||||
|
||||
/ *return _compilation.GetDiagnostics().Select(d => new {
|
||||
Message = d.GetMessage()
|
||||
});* /
|
||||
}*/
|
||||
|
||||
public async Task DisposeAsync() {
|
||||
using (_disposing) {
|
||||
_disposing.Cancel();
|
||||
//await _compilationLoopTask.ConfigureAwait(false);
|
||||
_workspace.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>c130c962-d17f-4741-b2b4-d74263bf380a</ProjectGuid>
|
||||
<RootNamespace>MirrorSharp</RootNamespace>
|
||||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
|
||||
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
|
@ -0,0 +1,19 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("MirrorSharp")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("c130c962-d17f-4741-b2b4-d74263bf380a")]
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"version": "0.9.0-*",
|
||||
|
||||
"dependencies": {
|
||||
"JetBrains.Annotations": "10.1.5",
|
||||
"Microsoft.AspNetCore.Http.Abstractions": "1.0.0",
|
||||
"Microsoft.CodeAnalysis.Common": "1.3.2",
|
||||
"Microsoft.CodeAnalysis.CSharp": "1.3.2",
|
||||
"Microsoft.CodeAnalysis.Workspaces.Common": "1.3.2",
|
||||
"Microsoft.CodeAnalysis.CSharp.Features": "1.3.2",
|
||||
"Newtonsoft.Json": "9.0.1",
|
||||
"NETStandard.Library": "1.6.0"
|
||||
},
|
||||
|
||||
"frameworks": {
|
||||
"netstandard1.6": {
|
||||
"imports": [ "dnxcore50", "portable-net45+win8+wp8+wpa81", "portable-net45+win8" ]
|
||||
}
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче