Merge branch 'dev' into dev_langservice

This commit is contained in:
Karl Burtram
2016-07-25 17:51:23 -07:00
72 changed files with 1255 additions and 463 deletions

View File

@@ -3,9 +3,9 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts;
namespace Microsoft.SqlTools.EditorServices.Connection
namespace Microsoft.SqlTools.ServiceLayer.Connection
{
/// <summary>
/// Message format for the initial connection request

View File

@@ -7,20 +7,47 @@ using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Threading.Tasks;
using Microsoft.SqlTools.EditorServices.Utility;
using Microsoft.SqlTools.ServiceLayer.Hosting;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol;
namespace Microsoft.SqlTools.EditorServices.Connection
namespace Microsoft.SqlTools.ServiceLayer.Connection
{
/// <summary>
/// Main class for the Connection Management services
/// </summary>
public class ConnectionService
{
#region Singleton Instance Implementation
/// <summary>
/// Singleton service instance
/// </summary>
private static Lazy<ConnectionService> instance
= new Lazy<ConnectionService>(() => new ConnectionService());
/// <summary>
/// Gets the singleton service instance
/// </summary>
public static ConnectionService Instance
{
get
{
return instance.Value;
}
}
/// <summary>
/// Default constructor is private since it's a singleton class
/// </summary>
private ConnectionService()
{
}
#endregion
#region Properties
/// <summary>
/// The SQL connection factory object
/// </summary>
@@ -60,17 +87,6 @@ namespace Microsoft.SqlTools.EditorServices.Connection
}
}
/// <summary>
/// Gets the singleton service instance
/// </summary>
public static ConnectionService Instance
{
get
{
return instance.Value;
}
}
/// <summary>
/// Gets the SQL connection factory instance
/// </summary>
@@ -86,12 +102,7 @@ namespace Microsoft.SqlTools.EditorServices.Connection
}
}
/// <summary>
/// Default constructor is private since it's a singleton class
/// </summary>
private ConnectionService()
{
}
#endregion
/// <summary>
/// Test constructor that injects dependency interfaces
@@ -102,6 +113,8 @@ namespace Microsoft.SqlTools.EditorServices.Connection
this.connectionFactory = testFactory;
}
#region Public Methods
/// <summary>
/// Open a connection with the specified connection details
/// </summary>
@@ -133,6 +146,12 @@ namespace Microsoft.SqlTools.EditorServices.Connection
};
}
public void Initialize(ServiceHost serviceHost)
{
// Register request and event handlers with the Service Host
serviceHost.SetRequestHandler(ConnectionRequest.Type, HandleConnectRequest);
}
/// <summary>
/// Add a new method to be called when the onconnection request is submitted
/// </summary>
@@ -140,7 +159,33 @@ namespace Microsoft.SqlTools.EditorServices.Connection
public void RegisterOnConnectionTask(OnConnectionHandler activity)
{
onConnectionActivities.Add(activity);
}
}
#endregion
#region Request Handlers
/// <summary>
/// Handle new connection requests
/// </summary>
/// <param name="connectionDetails"></param>
/// <param name="requestContext"></param>
/// <returns></returns>
protected async Task HandleConnectRequest(
ConnectionDetails connectionDetails,
RequestContext<ConnectionResult> requestContext)
{
Logger.Write(LogLevel.Verbose, "HandleConnectRequest");
// open connection base on request details
ConnectionResult result = ConnectionService.Instance.Connect(connectionDetails);
await requestContext.SendResult(result);
}
#endregion
#region Private Helpers
/// <summary>
/// Build a connection string from a connection details instance
@@ -156,5 +201,7 @@ namespace Microsoft.SqlTools.EditorServices.Connection
connectionBuilder["Initial Catalog"] = connectionDetails.DatabaseName;
return connectionBuilder.ToString();
}
#endregion
}
}

View File

@@ -5,7 +5,7 @@
using System.Collections.Generic;
namespace Microsoft.SqlTools.EditorServices.Connection
namespace Microsoft.SqlTools.ServiceLayer.Connection
{
/// <summary>
/// Interface for the SQL Connection factory

View File

@@ -7,7 +7,7 @@ using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
namespace Microsoft.SqlTools.EditorServices.Connection
namespace Microsoft.SqlTools.ServiceLayer.Connection
{
/// <summary>
/// Factory class to create SqlClientConnections

View File

@@ -4,7 +4,7 @@
//
namespace Microsoft.SqlTools.EditorServices.Protocol.LanguageServer
namespace Microsoft.SqlTools.ServiceLayer.Hosting.Contracts
{
/// <summary>
/// Defines a class that describes the capabilities of a language

View File

@@ -3,9 +3,9 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts;
namespace Microsoft.SqlTools.EditorServices.Protocol.LanguageServer
namespace Microsoft.SqlTools.ServiceLayer.Hosting.Contracts
{
public class InitializeRequest
{

View File

@@ -3,7 +3,7 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
namespace Microsoft.SqlTools.EditorServices.Protocol.LanguageServer
namespace Microsoft.SqlTools.ServiceLayer.Hosting.Contracts
{
public class ServerCapabilities
{

View File

@@ -3,9 +3,9 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts;
namespace Microsoft.SqlTools.EditorServices.Protocol.LanguageServer
namespace Microsoft.SqlTools.ServiceLayer.Hosting.Contracts
{
/// <summary>
/// Defines a message that is sent from the client to request

View File

@@ -3,10 +3,10 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol.Serializers;
using System.Threading.Tasks;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Serializers;
namespace Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol.Channel
namespace Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Channel
{
/// <summary>
/// Defines a base implementation for servers and their clients over a

View File

@@ -7,8 +7,9 @@ using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Serializers;
namespace Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol.Channel
namespace Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Channel
{
/// <summary>
/// Provides a client implementation for the standard I/O channel.

View File

@@ -6,8 +6,9 @@
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Serializers;
namespace Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol.Channel
namespace Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Channel
{
/// <summary>
/// Provides a server implementation for the standard I/O channel.

View File

@@ -6,7 +6,7 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
namespace Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol
namespace Microsoft.SqlTools.ServiceLayer.Hosting.Protocol
{
public static class Constants
{

View File

@@ -3,7 +3,7 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
namespace Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol
namespace Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts
{
/// <summary>
/// Defines an event type with a particular method name.

View File

@@ -6,7 +6,7 @@
using System.Diagnostics;
using Newtonsoft.Json.Linq;
namespace Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol
namespace Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts
{
/// <summary>
/// Defines all possible message types.

View File

@@ -5,7 +5,7 @@
using System.Diagnostics;
namespace Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol
namespace Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts
{
[DebuggerDisplay("RequestType MethodName = {MethodName}")]
public class RequestType<TParams, TResult>

View File

@@ -4,8 +4,9 @@
//
using System.Threading.Tasks;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts;
namespace Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol
namespace Microsoft.SqlTools.ServiceLayer.Hosting.Protocol
{
/// <summary>
/// Provides context for a received event so that handlers

View File

@@ -4,8 +4,9 @@
//
using System.Threading.Tasks;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts;
namespace Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol
namespace Microsoft.SqlTools.ServiceLayer.Hosting.Protocol
{
internal interface IMessageSender
{

View File

@@ -3,15 +3,16 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol.Channel;
using Microsoft.SqlTools.EditorServices.Utility;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Channel;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts;
using Microsoft.SqlTools.EditorServices.Utility;
namespace Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol
namespace Microsoft.SqlTools.ServiceLayer.Hosting.Protocol
{
public class MessageDispatcher
{

View File

@@ -5,7 +5,7 @@
using System;
namespace Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol
namespace Microsoft.SqlTools.ServiceLayer.Hosting.Protocol
{
public class MessageParseException : Exception
{

View File

@@ -3,7 +3,7 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
namespace Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol
namespace Microsoft.SqlTools.ServiceLayer.Hosting.Protocol
{
/// <summary>
/// Defines the possible message protocol types.

View File

@@ -3,16 +3,18 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.SqlTools.EditorServices.Utility;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Microsoft.SqlTools.EditorServices.Utility;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Serializers;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol
namespace Microsoft.SqlTools.ServiceLayer.Hosting.Protocol
{
public class MessageReader
{

View File

@@ -3,14 +3,16 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.SqlTools.EditorServices.Utility;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Microsoft.SqlTools.EditorServices.Utility;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Serializers;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol
namespace Microsoft.SqlTools.ServiceLayer.Hosting.Protocol
{
public class MessageWriter
{

View File

@@ -3,13 +3,14 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol.Channel;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Channel;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts;
namespace Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol
namespace Microsoft.SqlTools.ServiceLayer.Hosting.Protocol
{
/// <summary>
/// Provides behavior for a client or server endpoint that

View File

@@ -3,10 +3,11 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Newtonsoft.Json.Linq;
using System.Threading.Tasks;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts;
using Newtonsoft.Json.Linq;
namespace Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol
namespace Microsoft.SqlTools.ServiceLayer.Hosting.Protocol
{
public class RequestContext<TResult>
{

View File

@@ -3,9 +3,10 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts;
using Newtonsoft.Json.Linq;
namespace Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol
namespace Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Serializers
{
/// <summary>
/// Defines a common interface for message serializers.

View File

@@ -3,9 +3,10 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts;
using Newtonsoft.Json.Linq;
namespace Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol.Serializers
namespace Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Serializers
{
/// <summary>
/// Serializes messages in the JSON RPC format. Used primarily

View File

@@ -5,8 +5,9 @@
using Newtonsoft.Json.Linq;
using System;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts;
namespace Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol.Serializers
namespace Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Serializers
{
/// <summary>
/// Serializes messages in the V8 format. Used primarily for debug adapters.

View File

@@ -0,0 +1,148 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
using System.Linq;
using System.Threading.Tasks;
using System.Collections.Generic;
using Microsoft.SqlTools.EditorServices.Utility;
using Microsoft.SqlTools.ServiceLayer.Hosting.Contracts;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Channel;
namespace Microsoft.SqlTools.ServiceLayer.Hosting
{
/// <summary>
/// SQL Tools VS Code Language Server request handler. Provides the entire JSON RPC
/// implementation for sending/receiving JSON requests and dispatching the requests to
/// handlers that are registered prior to startup.
/// </summary>
public sealed class ServiceHost : ServiceHostBase
{
#region Singleton Instance Code
/// <summary>
/// Singleton instance of the service host for internal storage
/// </summary>
private static readonly Lazy<ServiceHost> instance = new Lazy<ServiceHost>(() => new ServiceHost());
/// <summary>
/// Current instance of the ServiceHost
/// </summary>
public static ServiceHost Instance
{
get { return instance.Value; }
}
/// <summary>
/// Constructs new instance of ServiceHost using the host and profile details provided.
/// Access is private to ensure only one instance exists at a time.
/// </summary>
private ServiceHost() : base(new StdioServerChannel())
{
// Initialize the shutdown activities
shutdownCallbacks = new List<ShutdownCallback>();
initializeCallbacks = new List<InitializeCallback>();
// Register the requests that this service host will handle
this.SetRequestHandler(InitializeRequest.Type, this.HandleInitializeRequest);
this.SetRequestHandler(ShutdownRequest.Type, this.HandleShutdownRequest);
}
#endregion
#region Member Variables
public delegate Task ShutdownCallback(object shutdownParams, RequestContext<object> shutdownRequestContext);
public delegate Task InitializeCallback(InitializeRequest startupParams, RequestContext<InitializeResult> requestContext);
private readonly List<ShutdownCallback> shutdownCallbacks;
private readonly List<InitializeCallback> initializeCallbacks;
#endregion
#region Public Methods
/// <summary>
/// Adds a new callback to be called when the shutdown request is submitted
/// </summary>
/// <param name="callback">Callback to perform when a shutdown request is submitted</param>
public void RegisterShutdownTask(ShutdownCallback callback)
{
shutdownCallbacks.Add(callback);
}
/// <summary>
/// Add a new method to be called when the initialize request is submitted
/// </summary>
/// <param name="callback">Callback to perform when an initialize request is submitted</param>
public void RegisterInitializeTask(InitializeCallback callback)
{
initializeCallbacks.Add(callback);
}
#endregion
#region Request Handlers
/// <summary>
/// Handles the shutdown event for the Language Server
/// </summary>
private async Task HandleShutdownRequest(object shutdownParams, RequestContext<object> requestContext)
{
Logger.Write(LogLevel.Normal, "Service host is shutting down...");
// Call all the shutdown methods provided by the service components
Task[] shutdownTasks = shutdownCallbacks.Select(t => t(shutdownParams, requestContext)).ToArray();
await Task.WhenAll(shutdownTasks);
}
/// <summary>
/// Handles the initialization request
/// </summary>
/// <param name="initializeParams"></param>
/// <param name="requestContext"></param>
/// <returns></returns>
private async Task HandleInitializeRequest(InitializeRequest initializeParams, RequestContext<InitializeResult> requestContext)
{
Logger.Write(LogLevel.Verbose, "HandleInitializationRequest");
// Call all tasks that registered on the initialize request
var initializeTasks = initializeCallbacks.Select(t => t(initializeParams, requestContext));
await Task.WhenAll(initializeTasks);
// TODO: Figure out where this needs to go to be agnostic of the language
// Send back what this server can do
await requestContext.SendResult(
new InitializeResult
{
Capabilities = new ServerCapabilities
{
TextDocumentSync = TextDocumentSyncKind.Incremental,
DefinitionProvider = true,
ReferencesProvider = true,
DocumentHighlightProvider = true,
DocumentSymbolProvider = true,
WorkspaceSymbolProvider = true,
HoverProvider = true,
CompletionProvider = new CompletionOptions
{
ResolveProvider = true,
TriggerCharacters = new string[] { ".", "-", ":", "\\" }
},
SignatureHelpProvider = new SignatureHelpOptions
{
TriggerCharacters = new string[] { " " } // TODO: Other characters here?
}
}
});
}
#endregion
}
}

View File

@@ -0,0 +1,47 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System.Threading.Tasks;
using Microsoft.SqlTools.ServiceLayer.Hosting.Contracts;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Channel;
namespace Microsoft.SqlTools.ServiceLayer.Hosting
{
public abstract class ServiceHostBase : ProtocolEndpoint
{
private bool isStarted;
private TaskCompletionSource<bool> serverExitedTask;
protected ServiceHostBase(ChannelBase serverChannel) :
base(serverChannel, MessageProtocolType.LanguageServer)
{
}
protected override Task OnStart()
{
// Register handlers for server lifetime messages
this.SetEventHandler(ExitNotification.Type, this.HandleExitNotification);
return Task.FromResult(true);
}
private async Task HandleExitNotification(
object exitParams,
EventContext eventContext)
{
// Stop the server channel
await this.Stop();
// Notify any waiter that the server has exited
if (this.serverExitedTask != null)
{
this.serverExitedTask.SetResult(true);
}
}
}
}

View File

@@ -0,0 +1,123 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.SqlTools.ServiceLayer.Connection;
using Microsoft.SqlTools.ServiceLayer.Hosting;
using Microsoft.SqlTools.ServiceLayer.LanguageServices.Contracts;
using Microsoft.SqlTools.ServiceLayer.WorkspaceServices.Contracts;
namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
{
/// <summary>
/// Main class for Autocomplete functionality
/// </summary>
public class AutoCompleteService
{
#region Singleton Instance Implementation
/// <summary>
/// Singleton service instance
/// </summary>
private static Lazy<AutoCompleteService> instance
= new Lazy<AutoCompleteService>(() => new AutoCompleteService());
/// <summary>
/// Gets the singleton service instance
/// </summary>
public static AutoCompleteService Instance
{
get
{
return instance.Value;
}
}
/// <summary>
/// Default, parameterless constructor.
/// TODO: Figure out how to make this truely singleton even with dependency injection for tests
/// </summary>
public AutoCompleteService()
{
}
#endregion
/// <summary>
/// Gets the current autocomplete candidate list
/// </summary>
public IEnumerable<string> AutoCompleteList { get; private set; }
public void InitializeService(ServiceHost serviceHost)
{
// Register a callback for when a connection is created
ConnectionService.Instance.RegisterOnConnectionTask(UpdateAutoCompleteCache);
}
/// <summary>
/// Update the cached autocomplete candidate list when the user connects to a database
/// </summary>
/// <param name="connection"></param>
public async Task UpdateAutoCompleteCache(ISqlConnection connection)
{
AutoCompleteList = connection.GetServerObjects();
await Task.FromResult(0);
}
/// <summary>
/// Return the completion item list for the current text position
/// </summary>
/// <param name="textDocumentPosition"></param>
public CompletionItem[] GetCompletionItems(TextDocumentPosition textDocumentPosition)
{
var completions = new List<CompletionItem>();
int i = 0;
// the completion list will be null is user not connected to server
if (this.AutoCompleteList != null)
{
foreach (var autoCompleteItem in this.AutoCompleteList)
{
// convert the completion item candidates into CompletionItems
completions.Add(new CompletionItem()
{
Label = autoCompleteItem,
Kind = CompletionItemKind.Keyword,
Detail = autoCompleteItem + " details",
Documentation = autoCompleteItem + " documentation",
TextEdit = new TextEdit
{
NewText = autoCompleteItem,
Range = new Range
{
Start = new Position
{
Line = textDocumentPosition.Position.Line,
Character = textDocumentPosition.Position.Character
},
End = new Position
{
Line = textDocumentPosition.Position.Line,
Character = textDocumentPosition.Position.Character + 5
}
}
}
});
// only show 50 items
if (++i == 50)
{
break;
}
}
}
return completions.ToArray();
}
}
}

View File

@@ -4,9 +4,10 @@
//
using System.Diagnostics;
using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts;
using Microsoft.SqlTools.ServiceLayer.WorkspaceServices.Contracts;
namespace Microsoft.SqlTools.EditorServices.Protocol.LanguageServer
namespace Microsoft.SqlTools.ServiceLayer.LanguageServices.Contracts
{
public class CompletionRequest
{

View File

@@ -3,9 +3,10 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts;
using Microsoft.SqlTools.ServiceLayer.WorkspaceServices.Contracts;
namespace Microsoft.SqlTools.EditorServices.Protocol.LanguageServer
namespace Microsoft.SqlTools.ServiceLayer.LanguageServices.Contracts
{
public class DefinitionRequest
{

View File

@@ -3,9 +3,10 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts;
using Microsoft.SqlTools.ServiceLayer.WorkspaceServices.Contracts;
namespace Microsoft.SqlTools.EditorServices.Protocol.LanguageServer
namespace Microsoft.SqlTools.ServiceLayer.LanguageServices.Contracts
{
public class PublishDiagnosticsNotification
{

View File

@@ -3,9 +3,10 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts;
using Microsoft.SqlTools.ServiceLayer.WorkspaceServices.Contracts;
namespace Microsoft.SqlTools.EditorServices.Protocol.LanguageServer
namespace Microsoft.SqlTools.ServiceLayer.LanguageServices.Contracts
{
public enum DocumentHighlightKind
{

View File

@@ -3,9 +3,9 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts;
namespace Microsoft.SqlTools.EditorServices.Protocol.LanguageServer
namespace Microsoft.SqlTools.ServiceLayer.LanguageServices.Contracts
{
public class ExpandAliasRequest
{

View File

@@ -3,10 +3,10 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol;
using System.Collections.Generic;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts;
namespace Microsoft.SqlTools.EditorServices.Protocol.LanguageServer
namespace Microsoft.SqlTools.ServiceLayer.LanguageServices.Contracts
{
public class FindModuleRequest
{

View File

@@ -3,9 +3,10 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts;
using Microsoft.SqlTools.ServiceLayer.WorkspaceServices.Contracts;
namespace Microsoft.SqlTools.EditorServices.Protocol.LanguageServer
namespace Microsoft.SqlTools.ServiceLayer.LanguageServices.Contracts
{
public class MarkedString
{

View File

@@ -3,9 +3,9 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts;
namespace Microsoft.SqlTools.EditorServices.Protocol.LanguageServer
namespace Microsoft.SqlTools.ServiceLayer.LanguageServices.Contracts
{
class InstallModuleRequest
{

View File

@@ -3,9 +3,10 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts;
using Microsoft.SqlTools.ServiceLayer.WorkspaceServices.Contracts;
namespace Microsoft.SqlTools.EditorServices.Protocol.LanguageServer
namespace Microsoft.SqlTools.ServiceLayer.LanguageServices.Contracts
{
public class ReferencesRequest
{

View File

@@ -3,9 +3,9 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts;
namespace Microsoft.SqlTools.EditorServices.Protocol.LanguageServer
namespace Microsoft.SqlTools.ServiceLayer.LanguageServices.Contracts
{
public class ShowOnlineHelpRequest
{

View File

@@ -3,9 +3,10 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts;
using Microsoft.SqlTools.ServiceLayer.WorkspaceServices.Contracts;
namespace Microsoft.SqlTools.EditorServices.Protocol.LanguageServer
namespace Microsoft.SqlTools.ServiceLayer.LanguageServices.Contracts
{
public class SignatureHelpRequest
{

View File

@@ -0,0 +1,442 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.SqlTools.EditorServices.Utility;
using Microsoft.SqlTools.ServiceLayer.Hosting;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol;
using Microsoft.SqlTools.ServiceLayer.LanguageServices.Contracts;
using Microsoft.SqlTools.ServiceLayer.SqlContext;
using Microsoft.SqlTools.ServiceLayer.WorkspaceServices;
using Microsoft.SqlTools.ServiceLayer.WorkspaceServices.Contracts;
using System.Linq;
using Microsoft.SqlServer.Management.SqlParser.Parser;
using Location = Microsoft.SqlTools.ServiceLayer.WorkspaceServices.Contracts.Location;
namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
{
/// <summary>
/// Main class for Language Service functionality including anything that reqires knowledge of
/// the language to perfom, such as definitions, intellisense, etc.
/// </summary>
public sealed class LanguageService
{
#region Singleton Instance Implementation
private static readonly Lazy<LanguageService> instance = new Lazy<LanguageService>(() => new LanguageService());
public static LanguageService Instance
{
get { return instance.Value; }
}
/// <summary>
/// Default, parameterless constructor.
/// TODO: Figure out how to make this truely singleton even with dependency injection for tests
/// </summary>
public LanguageService()
{
}
#endregion
#region Properties
private static CancellationTokenSource ExistingRequestCancellation { get; set; }
private SqlToolsSettings CurrentSettings
{
get { return WorkspaceService<SqlToolsSettings>.Instance.CurrentSettings; }
}
private Workspace CurrentWorkspace
{
get { return WorkspaceService<SqlToolsSettings>.Instance.Workspace; }
}
/// <summary>
/// Gets or sets the current SQL Tools context
/// </summary>
/// <returns></returns>
private SqlToolsContext Context { get; set; }
/// <summary>
/// The cached parse result from previous incremental parse
/// </summary>
private ParseResult prevParseResult;
#endregion
#region Public Methods
public void InitializeService(ServiceHost serviceHost, SqlToolsContext context)
{
// Register the requests that this service will handle
serviceHost.SetRequestHandler(DefinitionRequest.Type, HandleDefinitionRequest);
serviceHost.SetRequestHandler(ReferencesRequest.Type, HandleReferencesRequest);
serviceHost.SetRequestHandler(CompletionRequest.Type, HandleCompletionRequest);
serviceHost.SetRequestHandler(CompletionResolveRequest.Type, HandleCompletionResolveRequest);
serviceHost.SetRequestHandler(SignatureHelpRequest.Type, HandleSignatureHelpRequest);
serviceHost.SetRequestHandler(DocumentHighlightRequest.Type, HandleDocumentHighlightRequest);
serviceHost.SetRequestHandler(HoverRequest.Type, HandleHoverRequest);
serviceHost.SetRequestHandler(DocumentSymbolRequest.Type, HandleDocumentSymbolRequest);
serviceHost.SetRequestHandler(WorkspaceSymbolRequest.Type, HandleWorkspaceSymbolRequest);
// Register a no-op shutdown task for validation of the shutdown logic
serviceHost.RegisterShutdownTask(async (shutdownParams, shutdownRequestContext) =>
{
Logger.Write(LogLevel.Verbose, "Shutting down language service");
await Task.FromResult(0);
});
// Register the configuration update handler
WorkspaceService<SqlToolsSettings>.Instance.RegisterConfigChangeCallback(HandleDidChangeConfigurationNotification);
// Store the SqlToolsContext for future use
Context = context;
}
/// <summary>
/// Gets a list of semantic diagnostic marks for the provided script file
/// </summary>
/// <param name="scriptFile"></param>
public ScriptFileMarker[] GetSemanticMarkers(ScriptFile scriptFile)
{
// parse current SQL file contents to retrieve a list of errors
ParseOptions parseOptions = new ParseOptions();
ParseResult parseResult = Parser.IncrementalParse(
scriptFile.Contents,
prevParseResult,
parseOptions);
// save previous result for next incremental parse
this.prevParseResult = parseResult;
// build a list of SQL script file markers from the errors
List<ScriptFileMarker> markers = new List<ScriptFileMarker>();
foreach (var error in parseResult.Errors)
{
markers.Add(new ScriptFileMarker()
{
Message = error.Message,
Level = ScriptFileMarkerLevel.Error,
ScriptRegion = new ScriptRegion()
{
File = scriptFile.FilePath,
StartLineNumber = error.Start.LineNumber,
StartColumnNumber = error.Start.ColumnNumber,
StartOffset = 0,
EndLineNumber = error.End.LineNumber,
EndColumnNumber = error.End.ColumnNumber,
EndOffset = 0
}
});
}
return markers.ToArray();
}
#endregion
#region Request Handlers
private static async Task HandleDefinitionRequest(
TextDocumentPosition textDocumentPosition,
RequestContext<Location[]> requestContext)
{
Logger.Write(LogLevel.Verbose, "HandleDefinitionRequest");
await Task.FromResult(true);
}
private static async Task HandleReferencesRequest(
ReferencesParams referencesParams,
RequestContext<Location[]> requestContext)
{
Logger.Write(LogLevel.Verbose, "HandleReferencesRequest");
await Task.FromResult(true);
}
private static async Task HandleCompletionRequest(
TextDocumentPosition textDocumentPosition,
RequestContext<CompletionItem[]> requestContext)
{
Logger.Write(LogLevel.Verbose, "HandleCompletionRequest");
await Task.FromResult(true);
}
private static async Task HandleCompletionResolveRequest(
CompletionItem completionItem,
RequestContext<CompletionItem> requestContext)
{
Logger.Write(LogLevel.Verbose, "HandleCompletionResolveRequest");
await Task.FromResult(true);
}
private static async Task HandleSignatureHelpRequest(
TextDocumentPosition textDocumentPosition,
RequestContext<SignatureHelp> requestContext)
{
Logger.Write(LogLevel.Verbose, "HandleSignatureHelpRequest");
await Task.FromResult(true);
}
private static async Task HandleDocumentHighlightRequest(
TextDocumentPosition textDocumentPosition,
RequestContext<DocumentHighlight[]> requestContext)
{
Logger.Write(LogLevel.Verbose, "HandleDocumentHighlightRequest");
await Task.FromResult(true);
}
private static async Task HandleHoverRequest(
TextDocumentPosition textDocumentPosition,
RequestContext<Hover> requestContext)
{
Logger.Write(LogLevel.Verbose, "HandleHoverRequest");
await Task.FromResult(true);
}
private static async Task HandleDocumentSymbolRequest(
TextDocumentIdentifier textDocumentIdentifier,
RequestContext<SymbolInformation[]> requestContext)
{
Logger.Write(LogLevel.Verbose, "HandleDocumentSymbolRequest");
await Task.FromResult(true);
}
private static async Task HandleWorkspaceSymbolRequest(
WorkspaceSymbolParams workspaceSymbolParams,
RequestContext<SymbolInformation[]> requestContext)
{
Logger.Write(LogLevel.Verbose, "HandleWorkspaceSymbolRequest");
await Task.FromResult(true);
}
#endregion
#region Handlers for Events from Other Services
public async Task HandleDidChangeConfigurationNotification(
SqlToolsSettings newSettings,
SqlToolsSettings oldSettings,
EventContext eventContext)
{
// If script analysis settings have changed we need to clear & possibly update the current diagnostic records.
bool oldScriptAnalysisEnabled = oldSettings.ScriptAnalysis.Enable.HasValue;
if ((oldScriptAnalysisEnabled != newSettings.ScriptAnalysis.Enable))
{
// If the user just turned off script analysis or changed the settings path, send a diagnostics
// event to clear the analysis markers that they already have.
if (!newSettings.ScriptAnalysis.Enable.Value)
{
ScriptFileMarker[] emptyAnalysisDiagnostics = new ScriptFileMarker[0];
foreach (var scriptFile in WorkspaceService<SqlToolsSettings>.Instance.Workspace.GetOpenedFiles())
{
await PublishScriptDiagnostics(scriptFile, emptyAnalysisDiagnostics, eventContext);
}
}
else
{
await this.RunScriptDiagnostics(CurrentWorkspace.GetOpenedFiles(), eventContext);
}
}
// Update the settings in the current
CurrentSettings.EnableProfileLoading = newSettings.EnableProfileLoading;
CurrentSettings.ScriptAnalysis.Update(newSettings.ScriptAnalysis, CurrentWorkspace.WorkspacePath);
}
#endregion
#region Private Helpers
/// <summary>
/// Runs script diagnostics on changed files
/// </summary>
/// <param name="filesToAnalyze"></param>
/// <param name="eventContext"></param>
private Task RunScriptDiagnostics(ScriptFile[] filesToAnalyze, EventContext eventContext)
{
if (!CurrentSettings.ScriptAnalysis.Enable.Value)
{
// If the user has disabled script analysis, skip it entirely
return Task.FromResult(true);
}
// If there's an existing task, attempt to cancel it
try
{
if (ExistingRequestCancellation != null)
{
// Try to cancel the request
ExistingRequestCancellation.Cancel();
// If cancellation didn't throw an exception,
// clean up the existing token
ExistingRequestCancellation.Dispose();
ExistingRequestCancellation = null;
}
}
catch (Exception e)
{
Logger.Write(
LogLevel.Error,
String.Format(
"Exception while cancelling analysis task:\n\n{0}",
e.ToString()));
TaskCompletionSource<bool> cancelTask = new TaskCompletionSource<bool>();
cancelTask.SetCanceled();
return cancelTask.Task;
}
// Create a fresh cancellation token and then start the task.
// We create this on a different TaskScheduler so that we
// don't block the main message loop thread.
ExistingRequestCancellation = new CancellationTokenSource();
Task.Factory.StartNew(
() =>
DelayThenInvokeDiagnostics(
750,
filesToAnalyze,
eventContext,
ExistingRequestCancellation.Token),
CancellationToken.None,
TaskCreationOptions.None,
TaskScheduler.Default);
return Task.FromResult(true);
}
/// <summary>
/// Actually run the script diagnostics after waiting for some small delay
/// </summary>
/// <param name="delayMilliseconds"></param>
/// <param name="filesToAnalyze"></param>
/// <param name="eventContext"></param>
/// <param name="cancellationToken"></param>
private async Task DelayThenInvokeDiagnostics(
int delayMilliseconds,
ScriptFile[] filesToAnalyze,
EventContext eventContext,
CancellationToken cancellationToken)
{
// First of all, wait for the desired delay period before
// analyzing the provided list of files
try
{
await Task.Delay(delayMilliseconds, cancellationToken);
}
catch (TaskCanceledException)
{
// If the task is cancelled, exit directly
return;
}
// If we've made it past the delay period then we don't care
// about the cancellation token anymore. This could happen
// when the user stops typing for long enough that the delay
// period ends but then starts typing while analysis is going
// on. It makes sense to send back the results from the first
// delay period while the second one is ticking away.
// Get the requested files
foreach (ScriptFile scriptFile in filesToAnalyze)
{
Logger.Write(LogLevel.Verbose, "Analyzing script file: " + scriptFile.FilePath);
ScriptFileMarker[] semanticMarkers = GetSemanticMarkers(scriptFile);
Logger.Write(LogLevel.Verbose, "Analysis complete.");
await PublishScriptDiagnostics(scriptFile, semanticMarkers, eventContext);
}
}
/// <summary>
/// Send the diagnostic results back to the host application
/// </summary>
/// <param name="scriptFile"></param>
/// <param name="semanticMarkers"></param>
/// <param name="eventContext"></param>
private static async Task PublishScriptDiagnostics(
ScriptFile scriptFile,
ScriptFileMarker[] semanticMarkers,
EventContext eventContext)
{
var allMarkers = scriptFile.SyntaxMarkers != null
? scriptFile.SyntaxMarkers.Concat(semanticMarkers)
: semanticMarkers;
// Always send syntax and semantic errors. We want to
// make sure no out-of-date markers are being displayed.
await eventContext.SendEvent(
PublishDiagnosticsNotification.Type,
new PublishDiagnosticsNotification
{
Uri = scriptFile.ClientFilePath,
Diagnostics =
allMarkers
.Select(GetDiagnosticFromMarker)
.ToArray()
});
}
/// <summary>
/// Convert a ScriptFileMarker to a Diagnostic that is Language Service compatible
/// </summary>
/// <param name="scriptFileMarker"></param>
/// <returns></returns>
private static Diagnostic GetDiagnosticFromMarker(ScriptFileMarker scriptFileMarker)
{
return new Diagnostic
{
Severity = MapDiagnosticSeverity(scriptFileMarker.Level),
Message = scriptFileMarker.Message,
Range = new Range
{
// TODO: What offsets should I use?
Start = new Position
{
Line = scriptFileMarker.ScriptRegion.StartLineNumber - 1,
Character = scriptFileMarker.ScriptRegion.StartColumnNumber - 1
},
End = new Position
{
Line = scriptFileMarker.ScriptRegion.EndLineNumber - 1,
Character = scriptFileMarker.ScriptRegion.EndColumnNumber - 1
}
}
};
}
/// <summary>
/// Map ScriptFileMarker severity to Diagnostic severity
/// </summary>
/// <param name="markerLevel"></param>
private static DiagnosticSeverity MapDiagnosticSeverity(ScriptFileMarkerLevel markerLevel)
{
switch (markerLevel)
{
case ScriptFileMarkerLevel.Error:
return DiagnosticSeverity.Error;
case ScriptFileMarkerLevel.Warning:
return DiagnosticSeverity.Warning;
case ScriptFileMarkerLevel.Information:
return DiagnosticSeverity.Information;
default:
return DiagnosticSeverity.Error;
}
}
#endregion
}
}

View File

@@ -2,11 +2,13 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using Microsoft.SqlTools.EditorServices.Protocol.Server;
using Microsoft.SqlTools.EditorServices.Session;
using Microsoft.SqlTools.EditorServices.Utility;
using Microsoft.SqlTools.ServiceLayer.Hosting;
using Microsoft.SqlTools.ServiceLayer.SqlContext;
using Microsoft.SqlTools.ServiceLayer.WorkspaceServices;
using Microsoft.SqlTools.ServiceLayer.LanguageServices;
namespace Microsoft.SqlTools.ServiceHost
namespace Microsoft.SqlTools.ServiceLayer
{
/// <summary>
/// Main application class for SQL Tools API Service Host executable
@@ -25,16 +27,24 @@ namespace Microsoft.SqlTools.ServiceHost
const string hostName = "SQL Tools Service Host";
const string hostProfileId = "SQLToolsService";
Version hostVersion = new Version(1,0);
Version hostVersion = new Version(1,0);
// set up the host details and profile paths
var hostDetails = new HostDetails(hostName, hostProfileId, hostVersion);
var profilePaths = new ProfilePaths(hostProfileId, "baseAllUsersPath", "baseCurrentUserPath");
SqlToolsContext sqlToolsContext = new SqlToolsContext(hostDetails, profilePaths);
// create and run the language server
var languageServer = new LanguageServer(hostDetails, profilePaths);
languageServer.Start().Wait();
languageServer.WaitForExit();
// Grab the instance of the service host
ServiceHost serviceHost = ServiceHost.Instance;
// Initialize the services that will be hosted here
WorkspaceService<SqlToolsSettings>.Instance.InitializeService(serviceHost);
AutoCompleteService.Instance.InitializeService(serviceHost);
LanguageService.Instance.InitializeService(serviceHost, sqlToolsContext);
// Start the service
serviceHost.Start().Wait();
serviceHost.WaitForExit();
}
}
}

View File

@@ -1,84 +0,0 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.SqlTools.EditorServices.Protocol.LanguageServer;
using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol;
using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol.Channel;
using System.Threading.Tasks;
namespace Microsoft.SqlTools.EditorServices.Protocol.Server
{
public abstract class LanguageServerBase : ProtocolEndpoint
{
private bool isStarted;
private ChannelBase serverChannel;
private TaskCompletionSource<bool> serverExitedTask;
public LanguageServerBase(ChannelBase serverChannel) :
base(serverChannel, MessageProtocolType.LanguageServer)
{
this.serverChannel = serverChannel;
}
protected override Task OnStart()
{
// Register handlers for server lifetime messages
this.SetRequestHandler(ShutdownRequest.Type, this.HandleShutdownRequest);
this.SetEventHandler(ExitNotification.Type, this.HandleExitNotification);
// Initialize the implementation class
this.Initialize();
return Task.FromResult(true);
}
protected override async Task OnStop()
{
await this.Shutdown();
}
/// <summary>
/// Overridden by the subclass to provide initialization
/// logic after the server channel is started.
/// </summary>
protected abstract void Initialize();
/// <summary>
/// Can be overridden by the subclass to provide shutdown
/// logic before the server exits. Subclasses do not need
/// to invoke or return the value of the base implementation.
/// </summary>
protected virtual Task Shutdown()
{
// No default implementation yet.
return Task.FromResult(true);
}
private async Task HandleShutdownRequest(
object shutdownParams,
RequestContext<object> requestContext)
{
// Allow the implementor to shut down gracefully
await this.Shutdown();
await requestContext.SendResult(new object());
}
private async Task HandleExitNotification(
object exitParams,
EventContext eventContext)
{
// Stop the server channel
await this.Stop();
// Notify any waiter that the server has exited
if (this.serverExitedTask != null)
{
this.serverExitedTask.SetResult(true);
}
}
}
}

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?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>
@@ -7,14 +7,13 @@
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>{0D61DC2B-DA66-441D-B9D0-F76C98F780F9}</ProjectGuid>
<RootNamespace>Microsoft.SqlTools.ServiceHost</RootNamespace>
<RootNamespace>Microsoft.SqlTools.ServiceLayer</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>
</Project>

View File

@@ -1,75 +0,0 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
using Microsoft.SqlTools.EditorServices.Session;
using Microsoft.SqlTools.LanguageSupport;
namespace Microsoft.SqlTools.EditorServices
{
/// <summary>
/// Manages a single session for all editor services. This
/// includes managing all open script files for the session.
/// </summary>
public class EditorSession : IDisposable
{
#region Properties
/// <summary>
/// Gets the Workspace instance for this session.
/// </summary>
public Workspace Workspace { get; private set; }
/// <summary>
/// Gets or sets the Language Service
/// </summary>
/// <returns></returns>
public LanguageService LanguageService { get; set; }
/// <summary>
/// Gets the SqlToolsContext instance for this session.
/// </summary>
public SqlToolsContext SqlToolsContext { get; private set; }
#endregion
#region Public Methods
/// <summary>
/// Starts the session using the provided IConsoleHost implementation
/// for the ConsoleService.
/// </summary>
/// <param name="hostDetails">
/// Provides details about the host application.
/// </param>
/// <param name="profilePaths">
/// An object containing the profile paths for the session.
/// </param>
public void StartSession(HostDetails hostDetails, ProfilePaths profilePaths)
{
// Initialize all services
this.SqlToolsContext = new SqlToolsContext(hostDetails, profilePaths);
this.LanguageService = new LanguageService(this.SqlToolsContext);
// Create a workspace to contain open files
this.Workspace = new Workspace(this.SqlToolsContext.SqlToolsVersion);
}
#endregion
#region IDisposable Implementation
/// <summary>
/// Disposes of any Runspaces that were created for the
/// services used in this session.
/// </summary>
public void Dispose()
{
}
#endregion
}
}

View File

@@ -1,41 +0,0 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
namespace Microsoft.SqlTools.EditorServices
{
/// <summary>
/// Enumerates the types of output lines that will be sent
/// to an IConsoleHost implementation.
/// </summary>
public enum OutputType
{
/// <summary>
/// A normal output line, usually written with the or Write-Host or
/// Write-Output cmdlets.
/// </summary>
Normal,
/// <summary>
/// A debug output line, written with the Write-Debug cmdlet.
/// </summary>
Debug,
/// <summary>
/// A verbose output line, written with the Write-Verbose cmdlet.
/// </summary>
Verbose,
/// <summary>
/// A warning output line, written with the Write-Warning cmdlet.
/// </summary>
Warning,
/// <summary>
/// An error output line, written with the Write-Error cmdlet or
/// as a result of some error during SqlTools pipeline execution.
/// </summary>
Error
}
}

View File

@@ -1,65 +0,0 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
namespace Microsoft.SqlTools.EditorServices
{
/// <summary>
/// Provides details about output that has been written to the
/// SqlTools host.
/// </summary>
public class OutputWrittenEventArgs
{
/// <summary>
/// Gets the text of the output.
/// </summary>
public string OutputText { get; private set; }
/// <summary>
/// Gets the type of the output.
/// </summary>
public OutputType OutputType { get; private set; }
/// <summary>
/// Gets a boolean which indicates whether a newline
/// should be written after the output.
/// </summary>
public bool IncludeNewLine { get; private set; }
/// <summary>
/// Gets the foreground color of the output text.
/// </summary>
public ConsoleColor ForegroundColor { get; private set; }
/// <summary>
/// Gets the background color of the output text.
/// </summary>
public ConsoleColor BackgroundColor { get; private set; }
/// <summary>
/// Creates an instance of the OutputWrittenEventArgs class.
/// </summary>
/// <param name="outputText">The text of the output.</param>
/// <param name="includeNewLine">A boolean which indicates whether a newline should be written after the output.</param>
/// <param name="outputType">The type of the output.</param>
/// <param name="foregroundColor">The foreground color of the output text.</param>
/// <param name="backgroundColor">The background color of the output text.</param>
public OutputWrittenEventArgs(
string outputText,
bool includeNewLine,
OutputType outputType,
ConsoleColor foregroundColor,
ConsoleColor backgroundColor)
{
this.OutputText = outputText;
this.IncludeNewLine = includeNewLine;
this.OutputType = outputType;
this.ForegroundColor = foregroundColor;
this.BackgroundColor = backgroundColor;
}
}
}

View File

@@ -5,7 +5,7 @@
using System;
namespace Microsoft.SqlTools.EditorServices.Session
namespace Microsoft.SqlTools.ServiceLayer.SqlContext
{
/// <summary>
/// Contains details about the current host application (most

View File

@@ -3,12 +3,11 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace Microsoft.SqlTools.EditorServices.Session
namespace Microsoft.SqlTools.ServiceLayer.SqlContext
{
/// <summary>
/// Provides profile path resolution behavior relative to the name

View File

@@ -5,8 +5,11 @@
using System;
namespace Microsoft.SqlTools.EditorServices.Session
namespace Microsoft.SqlTools.ServiceLayer.SqlContext
{
/// <summary>
/// Context for SQL Tools
/// </summary>
public class SqlToolsContext
{
/// <summary>

View File

@@ -1,25 +1,29 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System.IO;
using System.IO;
using Microsoft.SqlTools.EditorServices.Utility;
namespace Microsoft.SqlTools.EditorServices.Protocol.Server
namespace Microsoft.SqlTools.ServiceLayer.SqlContext
{
public class LanguageServerSettings
/// <summary>
/// Class for serialization and deserialization of the settings the SQL Tools Service needs.
/// </summary>
public class SqlToolsSettings
{
public bool EnableProfileLoading { get; set; }
// TODO: Is this needed? I can't make sense of this comment.
// NOTE: This property is capitalized as 'SqlTools' because the
// mode name sent from the client is written as 'SqlTools' and
// JSON.net is using camelCasing.
//public ServiceHostSettings SqlTools { get; set; }
public ScriptAnalysisSettings ScriptAnalysis { get; set; }
public LanguageServerSettings()
public SqlToolsSettings()
{
this.ScriptAnalysis = new ScriptAnalysisSettings();
}
public void Update(LanguageServerSettings settings, string workspaceRootPath)
public bool EnableProfileLoading { get; set; }
public ScriptAnalysisSettings ScriptAnalysis { get; set; }
public void Update(SqlToolsSettings settings, string workspaceRootPath)
{
if (settings != null)
{
@@ -28,8 +32,10 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server
}
}
}
/// <summary>
/// Sub class for serialization and deserialization of script analysis settings
/// </summary>
public class ScriptAnalysisSettings
{
public bool? Enable { get; set; }
@@ -77,14 +83,4 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server
}
}
}
public class LanguageServerSettingsWrapper
{
// NOTE: This property is capitalized as 'SqlTools' because the
// mode name sent from the client is written as 'SqlTools' and
// JSON.net is using camelCasing.
public LanguageServerSettings SqlTools { get; set; }
}
}

View File

@@ -5,7 +5,7 @@
using System.Diagnostics;
namespace Microsoft.SqlTools.EditorServices
namespace Microsoft.SqlTools.ServiceLayer.WorkspaceServices.Contracts
{
/// <summary>
/// Provides details about a position in a file buffer. All

View File

@@ -6,7 +6,7 @@
using System;
using System.Diagnostics;
namespace Microsoft.SqlTools.EditorServices
namespace Microsoft.SqlTools.ServiceLayer.WorkspaceServices.Contracts
{
/// <summary>
/// Provides details about a range between two positions in

View File

@@ -3,9 +3,9 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts;
namespace Microsoft.SqlTools.EditorServices.Protocol.LanguageServer
namespace Microsoft.SqlTools.ServiceLayer.WorkspaceServices.Contracts
{
public class DidChangeConfigurationNotification<TConfig>
{

View File

@@ -3,7 +3,7 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
namespace Microsoft.SqlTools.EditorServices
namespace Microsoft.SqlTools.ServiceLayer.WorkspaceServices.Contracts
{
/// <summary>
/// Contains details relating to a content change in an open file.

View File

@@ -3,7 +3,7 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
namespace Microsoft.SqlTools.EditorServices
namespace Microsoft.SqlTools.ServiceLayer.WorkspaceServices.Contracts
{
/// <summary>
/// Provides details and operations for a buffer position in a

View File

@@ -9,19 +9,13 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace Microsoft.SqlTools.EditorServices
namespace Microsoft.SqlTools.ServiceLayer.WorkspaceServices.Contracts
{
/// <summary>
/// Contains the details and contents of an open script file.
/// </summary>
public class ScriptFile
{
#region Private Fields
private Version SqlToolsVersion;
#endregion
#region Properties
/// <summary>
@@ -120,18 +114,15 @@ namespace Microsoft.SqlTools.EditorServices
/// <param name="filePath">The path at which the script file resides.</param>
/// <param name="clientFilePath">The path which the client uses to identify the file.</param>
/// <param name="textReader">The TextReader to use for reading the file's contents.</param>
/// <param name="SqlToolsVersion">The version of SqlTools for which the script is being parsed.</param>
public ScriptFile(
string filePath,
string clientFilePath,
TextReader textReader,
Version SqlToolsVersion)
TextReader textReader)
{
this.FilePath = filePath;
this.ClientFilePath = clientFilePath;
this.IsAnalysisEnabled = true;
this.IsInMemory = Workspace.IsPathInMemory(filePath);
this.SqlToolsVersion = SqlToolsVersion;
this.SetFileContents(textReader.ReadToEnd());
}
@@ -142,17 +133,14 @@ namespace Microsoft.SqlTools.EditorServices
/// <param name="filePath">The path at which the script file resides.</param>
/// <param name="clientFilePath">The path which the client uses to identify the file.</param>
/// <param name="initialBuffer">The initial contents of the script file.</param>
/// <param name="SqlToolsVersion">The version of SqlTools for which the script is being parsed.</param>
public ScriptFile(
string filePath,
string clientFilePath,
string initialBuffer,
Version SqlToolsVersion)
string initialBuffer)
{
this.FilePath = filePath;
this.ClientFilePath = clientFilePath;
this.IsAnalysisEnabled = true;
this.SqlToolsVersion = SqlToolsVersion;
this.SetFileContents(initialBuffer);
}

View File

@@ -3,7 +3,7 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
namespace Microsoft.SqlTools.EditorServices
namespace Microsoft.SqlTools.ServiceLayer.WorkspaceServices.Contracts
{
/// <summary>
/// Defines the message level of a script file marker.

View File

@@ -5,7 +5,7 @@
//using System.Management.Automation.Language;
namespace Microsoft.SqlTools.EditorServices
namespace Microsoft.SqlTools.ServiceLayer.WorkspaceServices.Contracts
{
/// <summary>
/// Contains details about a specific region of text in script file.

View File

@@ -4,9 +4,9 @@
//
using System.Diagnostics;
using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts;
namespace Microsoft.SqlTools.EditorServices.Protocol.LanguageServer
namespace Microsoft.SqlTools.ServiceLayer.WorkspaceServices.Contracts
{
/// <summary>
/// Defines a base parameter class for identifying a text document.

View File

@@ -3,9 +3,9 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts;
namespace Microsoft.SqlTools.EditorServices.Protocol.LanguageServer
namespace Microsoft.SqlTools.ServiceLayer.WorkspaceServices.Contracts
{
public enum SymbolKind
{

View File

@@ -3,25 +3,25 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.SqlTools.EditorServices.Utility;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Linq;
using Microsoft.SqlTools.EditorServices.Utility;
using Microsoft.SqlTools.ServiceLayer.WorkspaceServices.Contracts;
namespace Microsoft.SqlTools.EditorServices
namespace Microsoft.SqlTools.ServiceLayer.WorkspaceServices
{
/// <summary>
/// Manages a "workspace" of script files that are open for a particular
/// editing session. Also helps to navigate references between ScriptFiles.
/// </summary>
public class Workspace
public class Workspace : IDisposable
{
#region Private Fields
#region Private Fields
private Version SqlToolsVersion;
private Dictionary<string, ScriptFile> workspaceFiles = new Dictionary<string, ScriptFile>();
#endregion
@@ -40,10 +40,8 @@ namespace Microsoft.SqlTools.EditorServices
/// <summary>
/// Creates a new instance of the Workspace class.
/// </summary>
/// <param name="SqlToolsVersion">The version of SqlTools for which scripts will be parsed.</param>
public Workspace(Version SqlToolsVersion)
public Workspace()
{
this.SqlToolsVersion = SqlToolsVersion;
}
#endregion
@@ -78,12 +76,7 @@ namespace Microsoft.SqlTools.EditorServices
using (FileStream fileStream = new FileStream(resolvedFilePath, FileMode.Open, FileAccess.Read))
using (StreamReader streamReader = new StreamReader(fileStream, Encoding.UTF8))
{
scriptFile =
new ScriptFile(
resolvedFilePath,
filePath,
streamReader,
this.SqlToolsVersion);
scriptFile = new ScriptFile(resolvedFilePath, filePath,streamReader);
this.workspaceFiles.Add(keyName, scriptFile);
}
@@ -169,12 +162,7 @@ namespace Microsoft.SqlTools.EditorServices
ScriptFile scriptFile = null;
if (!this.workspaceFiles.TryGetValue(keyName, out scriptFile))
{
scriptFile =
new ScriptFile(
resolvedFilePath,
filePath,
initialBuffer,
this.SqlToolsVersion);
scriptFile = new ScriptFile(resolvedFilePath, filePath, initialBuffer);
this.workspaceFiles.Add(keyName, scriptFile);
@@ -244,5 +232,17 @@ namespace Microsoft.SqlTools.EditorServices
}
#endregion
#region IDisposable Implementation
/// <summary>
/// Disposes of any Runspaces that were created for the
/// services used in this session.
/// </summary>
public void Dispose()
{
}
#endregion
}
}

View File

@@ -0,0 +1,235 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.SqlTools.EditorServices.Utility;
using Microsoft.SqlTools.ServiceLayer.Hosting;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol;
using Microsoft.SqlTools.ServiceLayer.WorkspaceServices.Contracts;
namespace Microsoft.SqlTools.ServiceLayer.WorkspaceServices
{
/// <summary>
/// Class for handling requests/events that deal with the state of the workspace, including the
/// opening and closing of files, the changing of configuration, etc.
/// </summary>
/// <typeparam name="TConfig">
/// The type of the class used for serializing and deserializing the configuration. Must be the
/// actual type of the instance otherwise deserialization will be incomplete.
/// </typeparam>
public class WorkspaceService<TConfig> where TConfig : class, new()
{
#region Singleton Instance Implementation
private static readonly Lazy<WorkspaceService<TConfig>> instance = new Lazy<WorkspaceService<TConfig>>(() => new WorkspaceService<TConfig>());
public static WorkspaceService<TConfig> Instance
{
get { return instance.Value; }
}
/// <summary>
/// Default, parameterless constructor.
/// TODO: Figure out how to make this truely singleton even with dependency injection for tests
/// </summary>
public WorkspaceService()
{
ConfigChangeCallbacks = new List<ConfigChangeCallback>();
TextDocChangeCallbacks = new List<TextDocChangeCallback>();
}
#endregion
#region Properties
public Workspace Workspace { get; private set; }
public TConfig CurrentSettings { get; private set; }
/// <summary>
/// Delegate for callbacks that occur when the configuration for the workspace changes
/// </summary>
/// <param name="newSettings">The settings that were just set</param>
/// <param name="oldSettings">The settings before they were changed</param>
/// <param name="eventContext">Context of the event that triggered the callback</param>
/// <returns></returns>
public delegate Task ConfigChangeCallback(TConfig newSettings, TConfig oldSettings, EventContext eventContext);
/// <summary>
/// Delegate for callbacks that occur when the current text document changes
/// </summary>
/// <param name="changedFiles">Array of files that changed</param>
/// <param name="eventContext">Context of the event raised for the changed files</param>
public delegate Task TextDocChangeCallback(ScriptFile[] changedFiles, EventContext eventContext);
/// <summary>
/// List of callbacks to call when the configuration of the workspace changes
/// </summary>
private List<ConfigChangeCallback> ConfigChangeCallbacks { get; set; }
/// <summary>
/// List of callbacks to call when the current text document changes
/// </summary>
private List<TextDocChangeCallback> TextDocChangeCallbacks { get; set; }
#endregion
#region Public Methods
public void InitializeService(ServiceHost serviceHost)
{
// Create a workspace that will handle state for the session
Workspace = new Workspace();
CurrentSettings = new TConfig();
// Register the handlers for when changes to the workspae occur
serviceHost.SetEventHandler(DidChangeTextDocumentNotification.Type, HandleDidChangeTextDocumentNotification);
serviceHost.SetEventHandler(DidOpenTextDocumentNotification.Type, HandleDidOpenTextDocumentNotification);
serviceHost.SetEventHandler(DidCloseTextDocumentNotification.Type, HandleDidCloseTextDocumentNotification);
serviceHost.SetEventHandler(DidChangeConfigurationNotification<TConfig>.Type, HandleDidChangeConfigurationNotification);
// Register an initialization handler that sets the workspace path
serviceHost.RegisterInitializeTask(async (parameters, contect) =>
{
Logger.Write(LogLevel.Verbose, "Initializing workspace service");
if (Workspace != null)
{
Workspace.WorkspacePath = parameters.RootPath;
}
await Task.FromResult(0);
});
// Register a shutdown request that disposes the workspace
serviceHost.RegisterShutdownTask(async (parameters, context) =>
{
Logger.Write(LogLevel.Verbose, "Shutting down workspace service");
if (Workspace != null)
{
Workspace.Dispose();
Workspace = null;
}
await Task.FromResult(0);
});
}
/// <summary>
/// Adds a new task to be called when the configuration has been changed. Use this to
/// handle changing configuration and changing the current configuration.
/// </summary>
/// <param name="task">Task to handle the request</param>
public void RegisterConfigChangeCallback(ConfigChangeCallback task)
{
ConfigChangeCallbacks.Add(task);
}
/// <summary>
/// Adds a new task to be called when the text of a document changes.
/// </summary>
/// <param name="task">Delegate to call when the document changes</param>
public void RegisterTextDocChangeCallback(TextDocChangeCallback task)
{
TextDocChangeCallbacks.Add(task);
}
#endregion
#region Event Handlers
/// <summary>
/// Handles text document change events
/// </summary>
protected Task HandleDidChangeTextDocumentNotification(
DidChangeTextDocumentParams textChangeParams,
EventContext eventContext)
{
StringBuilder msg = new StringBuilder();
msg.Append("HandleDidChangeTextDocumentNotification");
List<ScriptFile> changedFiles = new List<ScriptFile>();
// A text change notification can batch multiple change requests
foreach (var textChange in textChangeParams.ContentChanges)
{
string fileUri = textChangeParams.TextDocument.Uri;
msg.AppendLine(String.Format(" File: {0}", fileUri));
ScriptFile changedFile = Workspace.GetFile(fileUri);
changedFile.ApplyChange(
GetFileChangeDetails(
textChange.Range.Value,
textChange.Text));
changedFiles.Add(changedFile);
}
Logger.Write(LogLevel.Verbose, msg.ToString());
var handlers = TextDocChangeCallbacks.Select(t => t(changedFiles.ToArray(), eventContext));
return Task.WhenAll(handlers);
}
protected Task HandleDidOpenTextDocumentNotification(
DidOpenTextDocumentNotification openParams,
EventContext eventContext)
{
Logger.Write(LogLevel.Verbose, "HandleDidOpenTextDocumentNotification");
return Task.FromResult(true);
}
protected Task HandleDidCloseTextDocumentNotification(
TextDocumentIdentifier closeParams,
EventContext eventContext)
{
Logger.Write(LogLevel.Verbose, "HandleDidCloseTextDocumentNotification");
return Task.FromResult(true);
}
/// <summary>
/// Handles the configuration change event
/// </summary>
protected async Task HandleDidChangeConfigurationNotification(
DidChangeConfigurationParams<TConfig> configChangeParams,
EventContext eventContext)
{
Logger.Write(LogLevel.Verbose, "HandleDidChangeConfigurationNotification");
// Propagate the changes to the event handlers
var configUpdateTasks = ConfigChangeCallbacks.Select(
t => t(configChangeParams.Settings, CurrentSettings, eventContext));
await Task.WhenAll(configUpdateTasks);
}
#endregion
#region Private Helpers
/// <summary>
/// Switch from 0-based offsets to 1 based offsets
/// </summary>
/// <param name="changeRange"></param>
/// <param name="insertString"></param>
private static FileChange GetFileChangeDetails(Range changeRange, string insertString)
{
// The protocol's positions are zero-based so add 1 to all offsets
return new FileChange
{
InsertString = insertString,
Line = changeRange.Start.Line + 1,
Offset = changeRange.Start.Character + 1,
EndLine = changeRange.End.Line + 1,
EndOffset = changeRange.End.Character + 1
};
}
#endregion
}
}

View File

@@ -7,7 +7,7 @@ using System.Threading.Tasks;
using Microsoft.SqlTools.Test.Utility;
using Xunit;
namespace Microsoft.SqlTools.Test.Connection
namespace Microsoft.SqlTools.ServiceLayer.Test.Connection
{
/// <summary>
/// Tests for the ServiceHost Connection Service tests

View File

@@ -3,14 +3,12 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.SqlTools.EditorServices;
using Microsoft.SqlTools.EditorServices.Session;
using Microsoft.SqlTools.LanguageSupport;
using Microsoft.SqlTools.Test.Connection;
using Microsoft.SqlTools.ServiceLayer.LanguageServices;
using Microsoft.SqlTools.ServiceLayer.WorkspaceServices.Contracts;
using Microsoft.SqlTools.Test.Utility;
using Xunit;
namespace Microsoft.SqlTools.Test.LanguageServer
namespace Microsoft.SqlTools.ServiceLayer.Test.LanguageServer
{
/// <summary>
/// Tests for the ServiceHost Language Service tests

View File

@@ -3,15 +3,16 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol;
using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol.Serializers;
using System;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol;
using HostingMessage = Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts.Message;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Serializers;
using Xunit;
namespace Microsoft.SqlTools.EditorServices.Test.Protocol.MessageProtocol
namespace Microsoft.SqlTools.ServiceLayer.Test.Message
{
public class MessageReaderWriterTests
{
@@ -38,7 +39,7 @@ namespace Microsoft.SqlTools.EditorServices.Test.Protocol.MessageProtocol
// Write the message and then roll back the stream to be read
// TODO: This will need to be redone!
await messageWriter.WriteMessage(Message.Event("testEvent", null));
await messageWriter.WriteMessage(HostingMessage.Event("testEvent", null));
outputStream.Seek(0, SeekOrigin.Begin);
string expectedHeaderString =
@@ -82,7 +83,7 @@ namespace Microsoft.SqlTools.EditorServices.Test.Protocol.MessageProtocol
inputStream.Flush();
inputStream.Seek(0, SeekOrigin.Begin);
Message messageResult = messageReader.ReadMessage().Result;
HostingMessage messageResult = messageReader.ReadMessage().Result;
Assert.Equal("testEvent", messageResult.Method);
inputStream.Dispose();
@@ -117,7 +118,7 @@ namespace Microsoft.SqlTools.EditorServices.Test.Protocol.MessageProtocol
// Read the written messages from the stream
for (int i = 0; i < overflowMessageCount; i++)
{
Message messageResult = messageReader.ReadMessage().Result;
HostingMessage messageResult = messageReader.ReadMessage().Result;
Assert.Equal("testEvent", messageResult.Method);
}
@@ -145,7 +146,7 @@ namespace Microsoft.SqlTools.EditorServices.Test.Protocol.MessageProtocol
inputStream.Flush();
inputStream.Seek(0, SeekOrigin.Begin);
Message messageResult = messageReader.ReadMessage().Result;
HostingMessage messageResult = messageReader.ReadMessage().Result;
Assert.Equal("testEvent", messageResult.Method);
inputStream.Dispose();

View File

@@ -3,19 +3,16 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol;
using System;
using System.Threading.Tasks;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol;
namespace Microsoft.SqlTools.EditorServices.Test.Protocol.MessageProtocol
namespace Microsoft.SqlTools.ServiceLayer.Test.Message
{
#region Request Types
internal class TestRequest
{
public Task ProcessMessage(
EditorSession editorSession,
MessageWriter messageWriter)
public Task ProcessMessage(MessageWriter messageWriter)
{
return Task.FromResult(false);
}

View File

@@ -7,7 +7,7 @@
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>2d771d16-9d85-4053-9f79-e2034737deef</ProjectGuid>
<RootNamespace>Microsoft.SqlTools.EditorServices.Test.Protocol</RootNamespace>
<RootNamespace>Microsoft.SqlTools.ServiceLayer.Test</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'==''">.\obj</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
@@ -15,5 +15,8 @@
<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>

View File

@@ -3,12 +3,12 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol;
using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol.Serializers;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Serializers;
using HostingMessage = Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts.Message;
using Newtonsoft.Json.Linq;
using Xunit;
namespace Microsoft.SqlTools.EditorServices.Test.Protocol.LanguageServer
namespace Microsoft.SqlTools.ServiceLayer.Test.ServiceHost
{
public class TestMessageContents
{
@@ -44,7 +44,7 @@ namespace Microsoft.SqlTools.EditorServices.Test.Protocol.LanguageServer
{
var messageObj =
this.messageSerializer.SerializeMessage(
Message.Request(
HostingMessage.Request(
MessageId,
MethodName,
MessageContent));
@@ -61,7 +61,7 @@ namespace Microsoft.SqlTools.EditorServices.Test.Protocol.LanguageServer
{
var messageObj =
this.messageSerializer.SerializeMessage(
Message.Event(
HostingMessage.Event(
MethodName,
MessageContent));
@@ -76,7 +76,7 @@ namespace Microsoft.SqlTools.EditorServices.Test.Protocol.LanguageServer
{
var messageObj =
this.messageSerializer.SerializeMessage(
Message.Response(
HostingMessage.Response(
MessageId,
null,
MessageContent));
@@ -92,7 +92,7 @@ namespace Microsoft.SqlTools.EditorServices.Test.Protocol.LanguageServer
{
var messageObj =
this.messageSerializer.SerializeMessage(
Message.ResponseError(
HostingMessage.ResponseError(
MessageId,
null,
MessageContent));

View File

@@ -7,9 +7,9 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.SqlTools.EditorServices.Connection;
using Microsoft.SqlTools.EditorServices.Session;
using Microsoft.SqlTools.LanguageSupport;
using Microsoft.SqlTools.ServiceLayer.Connection;
using Microsoft.SqlTools.ServiceLayer.LanguageServices;
using Microsoft.SqlTools.ServiceLayer.SqlContext;
using Xunit;
namespace Microsoft.SqlTools.Test.Utility