simplify server startup logic by making IObservableServiceClient.Provider into a observable value
This commit is contained in:
Родитель
e0e71c4967
Коммит
b43876dfc6
|
@ -36,7 +36,6 @@ vs {
|
|||
':CodeEditor.Composition',
|
||||
':CodeEditor.IO',
|
||||
':CodeEditor.Testing',
|
||||
':CodeEditor.Composition.Client',
|
||||
':CodeEditor.Composition.Server',
|
||||
':CodeEditor.Reactive',
|
||||
':CodeEditor.Logging',
|
||||
|
@ -125,6 +124,7 @@ ext {
|
|||
project(':CodeEditor.Logging'),
|
||||
project(':CodeEditor.Composition'),
|
||||
project(':CodeEditor.ContentTypes'),
|
||||
project(':CodeEditor.Reactive'),
|
||||
project(':CodeEditor.Text.Data'),
|
||||
project(':CodeEditor.Text.Logic'),
|
||||
project(':CodeEditor.Text.UI'),
|
||||
|
|
|
@ -15,12 +15,12 @@ namespace CodeEditor.Composition.Server
|
|||
{
|
||||
static void Main()
|
||||
{
|
||||
using (var pidFileWriter = new StreamWriter(File.Open(PidFile, FileMode.Create, FileAccess.Write, FileShare.Read)))
|
||||
using (var uriFileWriter = new StreamWriter(File.Open(UriFilePath, FileMode.Create, FileAccess.Write, FileShare.Read)))
|
||||
{
|
||||
var baseUri = "http://localhost:8888/";
|
||||
const string baseUri = "http://localhost:8888/";
|
||||
|
||||
pidFileWriter.Write(baseUri);
|
||||
pidFileWriter.Flush();
|
||||
uriFileWriter.WriteLine(baseUri);
|
||||
uriFileWriter.Flush();
|
||||
|
||||
using (var appHost = new AppHost(DirectoryCatalog.AllAssembliesIn(ServerDirectory)))
|
||||
{
|
||||
|
@ -38,9 +38,9 @@ namespace CodeEditor.Composition.Server
|
|||
get { return Path.GetDirectoryName(FullyQualifiedName); }
|
||||
}
|
||||
|
||||
protected static string PidFile
|
||||
protected static string UriFilePath
|
||||
{
|
||||
get { return Path.ChangeExtension(FullyQualifiedName, "pid"); }
|
||||
get { return Path.ChangeExtension(FullyQualifiedName, "uri"); }
|
||||
}
|
||||
|
||||
private static string FullyQualifiedName
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using CodeEditor.Composition;
|
||||
|
||||
namespace CodeEditor.IO
|
||||
|
@ -10,12 +9,11 @@ namespace CodeEditor.IO
|
|||
IProcess StartManagedProcess(string executable);
|
||||
}
|
||||
|
||||
public interface IProcess
|
||||
public interface IProcess : IDisposable
|
||||
{
|
||||
int Id { get; }
|
||||
StreamReader StandardOutput { get; }
|
||||
StreamWriter StandardInput { get; }
|
||||
bool WaitForExit(int timeout);
|
||||
void Kill();
|
||||
}
|
||||
|
||||
[Export(typeof(IShell))]
|
||||
|
@ -23,15 +21,17 @@ namespace CodeEditor.IO
|
|||
{
|
||||
public IProcess StartManagedProcess(string executable)
|
||||
{
|
||||
var mono = Environment.GetEnvironmentVariable("MONO_EXECUTABLE") ?? "mono";
|
||||
return new StandardProcess(Process.Start(new ProcessStartInfo(mono, executable)
|
||||
return new StandardProcess(Process.Start(new ProcessStartInfo(MonoExecutable, executable)
|
||||
{
|
||||
RedirectStandardInput = true,
|
||||
RedirectStandardOutput = true,
|
||||
UseShellExecute = false
|
||||
WindowStyle = ProcessWindowStyle.Minimized
|
||||
}));
|
||||
}
|
||||
|
||||
static string MonoExecutable
|
||||
{
|
||||
get { return Environment.GetEnvironmentVariable("MONO_EXECUTABLE") ?? "mono"; }
|
||||
}
|
||||
|
||||
public class StandardProcess : IProcess
|
||||
{
|
||||
private readonly Process _process;
|
||||
|
@ -46,20 +46,20 @@ namespace CodeEditor.IO
|
|||
get { return _process.Id; }
|
||||
}
|
||||
|
||||
public StreamReader StandardOutput
|
||||
{
|
||||
get { return _process.StandardOutput; }
|
||||
}
|
||||
|
||||
public StreamWriter StandardInput
|
||||
{
|
||||
get { return _process.StandardInput; }
|
||||
}
|
||||
|
||||
public bool WaitForExit(int timeout)
|
||||
{
|
||||
return _process.WaitForExit(timeout);
|
||||
}
|
||||
|
||||
public void Kill()
|
||||
{
|
||||
_process.Kill();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_process.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using CodeEditor.IO;
|
||||
using CodeEditor.Logging;
|
||||
using CodeEditor.Reactive;
|
||||
using CodeEditor.Testing;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace CodeEditor.Languages.Common.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class ObservableServiceClientProviderTest : MockBasedTest
|
||||
{
|
||||
[Test]
|
||||
public void GetsServerAddressFromUriFile()
|
||||
{
|
||||
const string serverExecutable = "server.exe";
|
||||
const string serverUrilFile = "server.uri";
|
||||
const string serverAddress = "tcp://localhost:4242/IServiceProvider";
|
||||
|
||||
var projectPathProvider = MockFor<IServerExecutableProvider>();
|
||||
projectPathProvider
|
||||
.SetupGet(_ => _.ServerExecutable)
|
||||
.Returns(serverExecutable);
|
||||
|
||||
// provider tries to delete pid file to decide if it needs
|
||||
// to start the server
|
||||
var fileSystem = MockFor<IFileSystem>();
|
||||
var uriFile = MockFor<IFile>();
|
||||
fileSystem
|
||||
.Setup(_ => _.FileFor(serverUrilFile))
|
||||
.Returns(uriFile.Object);
|
||||
|
||||
uriFile
|
||||
.Setup(_ => _.Delete())
|
||||
.Throws(new IOException());
|
||||
|
||||
uriFile
|
||||
.Setup(_ => _.ReadAllText())
|
||||
.Returns(serverAddress + "\n");
|
||||
|
||||
var subject = new ObservableServiceClientProvider
|
||||
{
|
||||
ServerExecutableProvider = projectPathProvider.Object,
|
||||
FileSystem = fileSystem.Object,
|
||||
Logger = new StandardLogger()
|
||||
};
|
||||
Assert.IsNotNull(subject.Client.FirstOrTimeout(TimeSpan.FromSeconds(1)));
|
||||
|
||||
VerifyAllMocks();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
using System.IO;
|
||||
using CodeEditor.Composition;
|
||||
using CodeEditor.IO;
|
||||
using CodeEditor.Logging;
|
||||
using CodeEditor.Testing;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace CodeEditor.Languages.Common.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class UnityProjectProviderTest : MockBasedTest
|
||||
{
|
||||
[Test]
|
||||
public void GetsProjectLocationFromLocationProviderAndAddressFromPidFile()
|
||||
{
|
||||
const string projectFolder = "/Project";
|
||||
const string serverAddress = "tcp://localhost:4242/IServiceProvider";
|
||||
|
||||
var projectPathProvider = MockFor<IUnityProjectPathProvider>();
|
||||
projectPathProvider
|
||||
.SetupGet(_ => _.Location)
|
||||
.Returns(projectFolder);
|
||||
|
||||
var pidFilePath = Path.Combine(projectFolder, "Library/CodeEditor/Server/CodeEditor.Composition.Server.pid");
|
||||
|
||||
// provider tries to delete pid file to decide if it needs
|
||||
// to start the server
|
||||
var fileSystem = MockFor<IFileSystem>();
|
||||
var pidFile = MockFor<IFile>();
|
||||
fileSystem
|
||||
.Setup(_ => _.FileFor(pidFilePath))
|
||||
.Returns(pidFile.Object);
|
||||
|
||||
pidFile
|
||||
.Setup(_ => _.Delete())
|
||||
.Throws(new IOException());
|
||||
|
||||
pidFile
|
||||
.Setup(_ => _.ReadAllText())
|
||||
.Returns(serverAddress);
|
||||
|
||||
var subject = new ObservableServiceClientProvider
|
||||
{
|
||||
ProjectPathProvider = projectPathProvider.Object,
|
||||
FileSystem = fileSystem.Object,
|
||||
Logger = new StandardLogger()
|
||||
};
|
||||
Assert.IsNotNull(subject.Client);
|
||||
|
||||
VerifyAllMocks();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +1,10 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using CodeEditor.Composition;
|
||||
using CodeEditor.Composition.Client;
|
||||
using CodeEditor.IO;
|
||||
using CodeEditor.Logging;
|
||||
using CodeEditor.Reactive;
|
||||
using CodeEditor.Reactive.Disposables;
|
||||
using CodeEditor.Server.Interface;
|
||||
using ServiceStack.Text;
|
||||
using IFile = CodeEditor.IO.IFile;
|
||||
|
@ -12,63 +13,74 @@ namespace CodeEditor.Languages.Common
|
|||
{
|
||||
public interface IObservableServiceClientProvider
|
||||
{
|
||||
IObservableServiceClient Client { get; }
|
||||
}
|
||||
|
||||
public interface IUnityProjectPathProvider
|
||||
{
|
||||
string Location { get; }
|
||||
IObservableX<IObservableServiceClient> Client { get; }
|
||||
}
|
||||
|
||||
[Export(typeof(IObservableServiceClientProvider))]
|
||||
public class ObservableServiceClientProvider : IObservableServiceClientProvider
|
||||
{
|
||||
private readonly Lazy<IObservableServiceClient> _client;
|
||||
|
||||
[Import]
|
||||
public IFileSystem FileSystem;
|
||||
|
||||
[Import]
|
||||
public IUnityProjectPathProvider ProjectPathProvider;
|
||||
|
||||
[Import]
|
||||
public ICompositionServerControllerFactory ControllerFactory;
|
||||
|
||||
[Import]
|
||||
public ILogger Logger;
|
||||
readonly Lazy<IFile> _serverUriFile;
|
||||
|
||||
public ObservableServiceClientProvider()
|
||||
{
|
||||
_client = new Lazy<IObservableServiceClient>(CreateClient);
|
||||
_serverUriFile = new Lazy<IFile>(() => FileSystem.FileFor(ServerUriFilePath));
|
||||
}
|
||||
|
||||
public IObservableServiceClient Client
|
||||
{
|
||||
get { return _client.Value; }
|
||||
}
|
||||
[Import]
|
||||
public IServerExecutableProvider ServerExecutableProvider { get; set; }
|
||||
|
||||
private IObservableServiceClient CreateClient()
|
||||
{
|
||||
try
|
||||
{
|
||||
EnsureCompositionServerIsRunning();
|
||||
[Import]
|
||||
public IFileSystem FileSystem { get; set; }
|
||||
|
||||
var baseUri = PidFile.ReadAllText();
|
||||
return new ObservableServiceClient(baseUri);
|
||||
}
|
||||
catch (Exception e)
|
||||
[Import]
|
||||
public IShell Shell { get; set; }
|
||||
|
||||
[Import]
|
||||
public ILogger Logger { get; set; }
|
||||
|
||||
public IObservableX<IObservableServiceClient> Client
|
||||
{
|
||||
get
|
||||
{
|
||||
Logger.LogError(e);
|
||||
throw;
|
||||
return
|
||||
CreateClient()
|
||||
.Catch(
|
||||
(Exception e) =>
|
||||
ObservableX
|
||||
.Throw<IObservableServiceClient>(e)
|
||||
.Delay(TimeSpan.FromMilliseconds(500)))
|
||||
.Retry();
|
||||
}
|
||||
}
|
||||
|
||||
private IFile PidFile
|
||||
IObservableX<IObservableServiceClient> CreateClient()
|
||||
{
|
||||
get { return FileSystem.FileFor(PidFilePath); }
|
||||
return ObservableX.CreateWithDisposable<IObservableServiceClient>(observer =>
|
||||
{
|
||||
try
|
||||
{
|
||||
EnsureCompositionServerIsRunning();
|
||||
var baseUri = FirstLineFromUriFile();
|
||||
observer.CompleteWith(new ObservableServiceClient(baseUri));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.LogError(e);
|
||||
observer.OnError(e);
|
||||
}
|
||||
return Disposable.Empty;
|
||||
});
|
||||
}
|
||||
|
||||
private void EnsureCompositionServerIsRunning()
|
||||
string FirstLineFromUriFile()
|
||||
{
|
||||
var content = UriFile.ReadAllText();
|
||||
if (content[content.Length - 1] != '\n')
|
||||
throw new InvalidOperationException("'{0}' is missing a line ending".Fmt(content));
|
||||
return content.Trim();
|
||||
}
|
||||
|
||||
void EnsureCompositionServerIsRunning()
|
||||
{
|
||||
if (IsRunning())
|
||||
{
|
||||
|
@ -78,44 +90,69 @@ namespace CodeEditor.Languages.Common
|
|||
StartCompositionContainer();
|
||||
}
|
||||
|
||||
private void StartCompositionContainer()
|
||||
IFile UriFile
|
||||
{
|
||||
var folder = Path.GetDirectoryName(CompositionServerExe);
|
||||
Logger.Log("Starting server at {0}".Fmt(folder));
|
||||
ControllerFactory.StartCompositionServerAtFolder(folder);
|
||||
get { return _serverUriFile.Value; }
|
||||
}
|
||||
|
||||
private bool IsRunning()
|
||||
void StartCompositionContainer()
|
||||
{
|
||||
return !TryToDeleteFilePidFile();
|
||||
var serverExe = ServerExecutable;
|
||||
Logger.Log("Starting {0}".Fmt(serverExe));
|
||||
using (Shell.StartManagedProcess(serverExe))
|
||||
{
|
||||
// this doesn't kill the actual process but
|
||||
// just releases any resources attached to
|
||||
// the object
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryToDeleteFilePidFile()
|
||||
bool IsRunning()
|
||||
{
|
||||
return !TryToDeleteUriFile();
|
||||
}
|
||||
|
||||
bool TryToDeleteUriFile()
|
||||
{
|
||||
try
|
||||
{
|
||||
PidFile.Delete();
|
||||
UriFile.Delete();
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private string PidFilePath
|
||||
string ServerUriFilePath
|
||||
{
|
||||
get { return Path.ChangeExtension(CompositionServerExe, "pid"); }
|
||||
get { return Path.ChangeExtension(ServerExecutable, "uri"); }
|
||||
}
|
||||
|
||||
private string CompositionServerExe
|
||||
string ServerExecutable
|
||||
{
|
||||
get { return Path.Combine(ProjectFolder, "Library/CodeEditor/Server/CodeEditor.Composition.Server.exe"); }
|
||||
get { return ServerExecutableProvider.ServerExecutable; }
|
||||
}
|
||||
}
|
||||
|
||||
public interface IServerExecutableProvider
|
||||
{
|
||||
string ServerExecutable { get; }
|
||||
}
|
||||
|
||||
public class ServerExecutableProvider : IServerExecutableProvider
|
||||
{
|
||||
readonly string _serverExecutable;
|
||||
|
||||
public ServerExecutableProvider(string serverExecutable)
|
||||
{
|
||||
_serverExecutable = serverExecutable;
|
||||
}
|
||||
|
||||
protected string ProjectFolder
|
||||
public string ServerExecutable
|
||||
{
|
||||
get { return ProjectPathProvider.Location; }
|
||||
get { return _serverExecutable; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,25 +7,25 @@ using CodeEditor.Text.UI;
|
|||
namespace CodeEditor.Languages.Common
|
||||
{
|
||||
[Export(typeof(INavigateToItemProvider))]
|
||||
internal class SymbolNavigateToItemProvider : INavigateToItemProvider
|
||||
public class SymbolNavigateToItemProvider : INavigateToItemProvider
|
||||
{
|
||||
[Import]
|
||||
public IObservableServiceClientProvider ServiceClientProvider;
|
||||
public IObservableServiceClientProvider ServiceClientProvider { get; set; }
|
||||
|
||||
[Import]
|
||||
public ILogger Logger;
|
||||
public ILogger Logger { get; set; }
|
||||
|
||||
public IObservableX<INavigateToItem> Search(string filter)
|
||||
{
|
||||
if (string.IsNullOrEmpty(filter))
|
||||
return ObservableX.Empty<INavigateToItem>();
|
||||
|
||||
return ServiceClient
|
||||
.ObserveMany(new SymbolSearch {Filter = filter})
|
||||
.Select(_ => (INavigateToItem)new SymbolItem(_));
|
||||
return string.IsNullOrEmpty(filter)
|
||||
? ObservableX.Empty<INavigateToItem>()
|
||||
: ServiceClient
|
||||
.SelectMany(
|
||||
(client) => client.ObserveMany(new SymbolSearch {Filter = filter}),
|
||||
(client, symbol) => (INavigateToItem) new SymbolItem(symbol));
|
||||
}
|
||||
|
||||
private IObservableServiceClient ServiceClient
|
||||
private IObservableX<IObservableServiceClient> ServiceClient
|
||||
{
|
||||
get { return ServiceClientProvider.Client; }
|
||||
}
|
||||
|
|
|
@ -8,5 +8,10 @@ namespace CodeEditor.Reactive.Disposables
|
|||
{
|
||||
return System.Disposables.Disposable.Create(dispose);
|
||||
}
|
||||
|
||||
public static IDisposable Empty
|
||||
{
|
||||
get { return System.Disposables.Disposable.Empty; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,6 +17,15 @@ namespace CodeEditor.Reactive
|
|||
void OnCompleted();
|
||||
}
|
||||
|
||||
public static class ObserverX
|
||||
{
|
||||
public static void CompleteWith<T>(this IObserverX<T> observer, T value)
|
||||
{
|
||||
observer.OnNext(value);
|
||||
observer.OnCompleted();
|
||||
}
|
||||
}
|
||||
|
||||
public static class ObservableX
|
||||
{
|
||||
public static IObservableX<T> ObserveOnThreadPool<T>(this IObservableX<T> source)
|
||||
|
@ -39,6 +48,16 @@ namespace CodeEditor.Reactive
|
|||
return Observable.Start(func).ToObservableX();
|
||||
}
|
||||
|
||||
public static IObservableX<T> Delay<T>(this IObservableX<T> source, TimeSpan dueTimeout)
|
||||
{
|
||||
return source.Map(_ => _.Delay(dueTimeout));
|
||||
}
|
||||
|
||||
public static IObservableX<T> Retry<T>(this IObservableX<T> source)
|
||||
{
|
||||
return source.Map(_ => _.Retry());
|
||||
}
|
||||
|
||||
public static IObservableX<T> Return<T>(T value)
|
||||
{
|
||||
return Observable.Return(value).ToObservableX();
|
||||
|
@ -79,6 +98,12 @@ namespace CodeEditor.Reactive
|
|||
Func<T, IObservable<TResult>> observableSelector = t => selector(t).ToObservable();
|
||||
return source.Map(_ => _.SelectMany(observableSelector));
|
||||
}
|
||||
|
||||
public static IObservableX<TResult> SelectMany<TSource, TCollection, TResult>(this IObservableX<TSource> source, Func<TSource, IObservableX<TCollection>> collectionSelector, Func<TSource, TCollection, TResult> resultSelector)
|
||||
{
|
||||
Func<TSource, IObservable<TCollection>> observableCollectionSelector = t => collectionSelector(t).ToObservable();
|
||||
return source.Map(_ => _.SelectMany(observableCollectionSelector, resultSelector));
|
||||
}
|
||||
|
||||
public static IObservableX<T> Where<T>(this IObservableX<T> source, Func<T, bool> predicate)
|
||||
{
|
||||
|
@ -90,6 +115,11 @@ namespace CodeEditor.Reactive
|
|||
return source.Map(_ => _.TakeWhile(predicate));
|
||||
}
|
||||
|
||||
public static IObservableX<T> Take<T>(this IObservableX<T> source, int count)
|
||||
{
|
||||
return source.Map(_ => _.Take(count));
|
||||
}
|
||||
|
||||
public static IObservableX<T> Do<T>(this IObservableX<T> source, Action<T> action)
|
||||
{
|
||||
return source.Map(_ => _.Do(action));
|
||||
|
@ -145,10 +175,20 @@ namespace CodeEditor.Reactive
|
|||
return Observable.Create<T>(observer => subscribe(observer.ToObserverX())).ToObservableX();
|
||||
}
|
||||
|
||||
public static IObservableX<T> CreateWithDisposable<T>(Func<IObserverX<T>, IDisposable> subscribe)
|
||||
{
|
||||
return Observable.CreateWithDisposable<T>(observer => subscribe(observer.ToObserverX())).ToObservableX();
|
||||
}
|
||||
|
||||
public static Func<IObservableX<TResult>> FromAsyncPattern<TResult>(Func<AsyncCallback, object, IAsyncResult> begin, Func<IAsyncResult, TResult> end)
|
||||
{
|
||||
var fromAsyncPattern = Observable.FromAsyncPattern(begin, end);
|
||||
return () => fromAsyncPattern().ToObservableX();
|
||||
}
|
||||
|
||||
public static IObservableX<TResult> Defer<TResult>(Func<IObservableX<TResult>> observableFactory)
|
||||
{
|
||||
return Observable.Defer(() => observableFactory().ToObservable()).ToObservableX();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ namespace CodeEditor.Server.Interface
|
|||
|
||||
public IObservableX<TResponse> ObserveMany<TResponse>(IReturn<IEnumerable<TResponse>> request)
|
||||
{
|
||||
return ObservableX.Create<TResponse>(observer =>
|
||||
return ObservableX.CreateWithDisposable<TResponse>(observer =>
|
||||
{
|
||||
var client = new JsonServiceClient(_baseUri) {Timeout = Timeout};
|
||||
var disposable = new MultipleAssignmentDisposable
|
||||
|
@ -47,7 +47,7 @@ namespace CodeEditor.Server.Interface
|
|||
observer.OnError(exception);
|
||||
});
|
||||
|
||||
return disposable.Dispose;
|
||||
return disposable;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,11 +31,6 @@ namespace CodeEditor.Server
|
|||
IUnityProject Project { get; }
|
||||
}
|
||||
|
||||
public interface IUnityAssetsFolderProvider
|
||||
{
|
||||
IFolder AssetsFolder { get; }
|
||||
}
|
||||
|
||||
[Export(typeof(IUnityProjectProvider))]
|
||||
class UnityProjectProvider : IUnityProjectProvider
|
||||
{
|
||||
|
@ -65,6 +60,11 @@ namespace CodeEditor.Server
|
|||
}
|
||||
}
|
||||
|
||||
public interface IUnityAssetsFolderProvider
|
||||
{
|
||||
IFolder AssetsFolder { get; }
|
||||
}
|
||||
|
||||
[Export(typeof(IUnityAssetsFolderProvider))]
|
||||
class ServerAssetsFolderProvider : IUnityAssetsFolderProvider
|
||||
{
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using CodeEditor.Composition;
|
||||
using CodeEditor.Composition.Hosting;
|
||||
using CodeEditor.IO;
|
||||
using CodeEditor.Logging;
|
||||
using CodeEditor.Text.UI.Unity.Engine;
|
||||
using CodeEditor.IO;
|
||||
using CodeEditor.Languages.Common;
|
||||
using CodeEditor.Logging;
|
||||
using CodeEditor.Text.UI.Unity.Engine;
|
||||
using UnityEditor;
|
||||
|
||||
namespace CodeEditor.Text.UI.Unity.Editor.Implementation
|
||||
|
@ -18,42 +20,54 @@ namespace CodeEditor.Text.UI.Unity.Editor.Implementation
|
|||
NavigatorWindow.ProviderAggregatorFactory = GetExportedValue<INavigateToItemProviderAggregator>;
|
||||
}
|
||||
|
||||
private static ITextView ViewForFile(string fileName)
|
||||
static ITextView ViewForFile(string fileName)
|
||||
{
|
||||
return GetExportedValue<ITextViewFactory>().ViewForFile(fileName);
|
||||
}
|
||||
|
||||
private static T GetExportedValue<T>()
|
||||
{
|
||||
static T GetExportedValue<T>()
|
||||
{
|
||||
return CompositionContainer.GetExportedValue<T>();
|
||||
}
|
||||
|
||||
private static CompositionContainer CompositionContainer
|
||||
static CompositionContainer CompositionContainer
|
||||
{
|
||||
get { return Container.Value; }
|
||||
}
|
||||
|
||||
private static readonly Lazy<CompositionContainer> Container = new Lazy<CompositionContainer>(CreateCompositionContainer);
|
||||
static readonly Lazy<CompositionContainer> Container = new Lazy<CompositionContainer>(CreateCompositionContainer);
|
||||
|
||||
private static CompositionContainer CreateCompositionContainer()
|
||||
static CompositionContainer CreateCompositionContainer()
|
||||
{
|
||||
var container = new CompositionContainer(AppDomain.CurrentDomain.GetAssemblies().ToArray());
|
||||
container.AddExportedValue<IFileSystem>(new UnityEditorFileSystem());
|
||||
container.AddExportedValue<ILogger>(new UnityLogger());
|
||||
container.AddExportedValue<IServerExecutableProvider>(new ServerExecutableProvider(ServerExecutable));
|
||||
if (UnityEngine.Debug.isDebugBuild)
|
||||
container.AddExportedValue<ILogger>(new UnityLogger());
|
||||
return container;
|
||||
}
|
||||
|
||||
private class UnityLogger : ILogger
|
||||
{
|
||||
public void Log(object value)
|
||||
{
|
||||
UnityEngine.Debug.Log(value);
|
||||
}
|
||||
|
||||
public void LogError(Exception exception)
|
||||
{
|
||||
UnityEngine.Debug.LogException(exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static string ServerExecutable
|
||||
{
|
||||
get { return Path.Combine(ProjectPath, "Library/CodeEditor/Server/CodeEditor.Composition.Server.exe"); }
|
||||
}
|
||||
|
||||
static string ProjectPath
|
||||
{
|
||||
get { return Path.GetDirectoryName(UnityEngine.Application.dataPath); }
|
||||
}
|
||||
|
||||
class UnityLogger : ILogger
|
||||
{
|
||||
public void Log(object value)
|
||||
{
|
||||
UnityEngine.Debug.Log(value);
|
||||
}
|
||||
|
||||
public void LogError(Exception exception)
|
||||
{
|
||||
UnityEngine.Debug.LogException(exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
using System.IO;
|
||||
using CodeEditor.Composition;
|
||||
using CodeEditor.Languages.Common;
|
||||
|
||||
namespace CodeEditor.Text.UI.Unity.Editor.Implementation
|
||||
{
|
||||
[Export(typeof(IUnityProjectPathProvider))]
|
||||
class UnityProjectPathProvider : IUnityProjectPathProvider
|
||||
{
|
||||
public string Location
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.GetDirectoryName(UnityEngine.Application.dataPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
4
todo.org
4
todo.org
|
@ -1,11 +1,7 @@
|
|||
* implement IShell.StartManagedProcess on top of Unity's MonoBleedingEdge
|
||||
* get mono from MONO_EXECUTABLE environment variable in the default case
|
||||
* kaizen Clr.exec should set MONO_EXECUTABLE
|
||||
* pass project folder as environment variable to CodeEditor.Composition.Server
|
||||
* integrate nrefactory for symbol search
|
||||
* implement streaming behaviour for ObservableServiceClient
|
||||
* move File search also to the server (using the client search only as a fallback)
|
||||
* move logging to CodeEditor.Logging
|
||||
* rename all Implementation folders to Internal
|
||||
* rename all gradle files to build.gradle
|
||||
* integrate undo
|
||||
|
|
Загрузка…
Ссылка в новой задаче