Enable file change tracking with Workspace and EditorSession.

Also include misc. clean-ups related to removing unneeded PowerShell Language Service code.
This commit is contained in:
Karl Burtram
2016-07-16 01:14:12 -07:00
parent f2bb986f42
commit 4ad506f6f2
10 changed files with 237 additions and 60 deletions

View File

@@ -18,7 +18,7 @@
"type": "coreclr",
"request": "attach",
"requireExactSource": false,
"processId": 14720
"processId": 17264
}
]
}

View File

@@ -61,12 +61,27 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.LanguageServer
public class DidChangeTextDocumentParams : TextDocumentIdentifier
{
public TextDocumentUriChangeEvent TextDocument { get; set; }
/// <summary>
/// Gets or sets the list of changes to the document content.
/// </summary>
public TextDocumentChangeEvent[] ContentChanges { get; set; }
}
public class TextDocumentUriChangeEvent
{
/// <summary>
/// Gets or sets the Uri of the changed text document
/// </summary>
public string Uri { get; set; }
/// <summary>
/// Gets or sets the Version of the changed text document
/// </summary>
public int Version { get; set; }
}
public class TextDocumentChangeEvent
{
/// <summary>

View File

@@ -18,7 +18,7 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol
#region Fields
private ChannelBase protocolChannel;
// private AsyncQueue<Message> messagesToWrite;
private AsyncContextThread messageLoopThread;
private Dictionary<string, Func<Message, MessageWriter, Task>> requestHandlers =

View File

@@ -3,10 +3,7 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
namespace Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol.Serializers
{

View File

@@ -3,8 +3,6 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;

View File

@@ -8,17 +8,23 @@ using Microsoft.SqlTools.EditorServices.Protocol.MessageProtocol.Channel;
using Microsoft.SqlTools.EditorServices.Session;
using System.Threading.Tasks;
using Microsoft.SqlTools.EditorServices.Utility;
using System.Collections.Generic;
using System.Text;
namespace Microsoft.SqlTools.EditorServices.Protocol.Server
{
public class LanguageServer : LanguageServerBase
{
private EditorSession editorSession;
/// <param name="hostDetails">
/// Provides details about the host application.
/// </param>
public LanguageServer(HostDetails hostDetails, ProfilePaths profilePaths)
: base(new StdioServerChannel())
{
this.editorSession = new EditorSession();
this.editorSession.StartSession(hostDetails, profilePaths);
}
protected override void Initialize()
@@ -43,6 +49,14 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server
protected override async Task Shutdown()
{
Logger.Write(LogLevel.Normal, "Language service is shutting down...");
if (this.editorSession != null)
{
this.editorSession.Dispose();
this.editorSession = null;
}
await Task.FromResult(true);
}
@@ -80,11 +94,46 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server
});
}
/// <summary>
/// Handles text document change events
/// </summary>
/// <param name="textChangeParams"></param>
/// <param name="eventContext"></param>
/// <returns></returns>
protected Task HandleDidChangeTextDocumentNotification(
DidChangeTextDocumentParams textChangeParams,
EventContext eventContext)
{
Logger.Write(LogLevel.Normal, "HandleDidChangeTextDocumentNotification");
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();
msg.Append(" File: ");
msg.Append(fileUri);
ScriptFile changedFile = editorSession.Workspace.GetFile(fileUri);
// changedFile.ApplyChange(
// GetFileChangeDetails(
// textChange.Range.Value,
// textChange.Text));
// changedFiles.Add(changedFile);
}
Logger.Write(LogLevel.Normal, msg.ToString());
// // TODO: Get all recently edited files in the workspace
// this.RunScriptDiagnostics(
// changedFiles.ToArray(),
// editorSession,
// eventContext);
return Task.FromResult(true);
}

View File

@@ -3,11 +3,8 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
// using Microsoft.SqlTools.EditorServices.Console;
// using Microsoft.SqlTools.EditorServices.Extensions;
using System;
using Microsoft.SqlTools.EditorServices.Session;
// using Microsoft.SqlTools.EditorServices.Utility;
// using System.IO;
namespace Microsoft.SqlTools.EditorServices
{
@@ -15,12 +12,8 @@ namespace Microsoft.SqlTools.EditorServices
/// Manages a single session for all editor services. This
/// includes managing all open script files for the session.
/// </summary>
public class EditorSession
public class EditorSession : IDisposable
{
public void StartSession(HostDetails hostDetails, ProfilePaths profilePaths)
{
}
#if false
#region Properties
/// <summary>
@@ -33,6 +26,59 @@ namespace Microsoft.SqlTools.EditorServices
/// </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);
// this.DebugService = new DebugService(this.SqlToolsContext);
// this.ConsoleService = new ConsoleService(this.SqlToolsContext);
// this.ExtensionService = new ExtensionService(this.SqlToolsContext);
// this.InstantiateAnalysisService();
// 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
#if false
#region Properties
/// <summary>
/// Gets the LanguageService instance for this session.
/// </summary>

View File

@@ -0,0 +1,25 @@
//
// 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.Session
{
public class SqlToolsContext
{
/// <summary>
/// Gets the PowerShell version of the current runspace.
/// </summary>
public Version SqlToolsVersion
{
get; private set;
}
public SqlToolsContext(HostDetails hostDetails, ProfilePaths profilePaths)
{
}
}
}

View File

@@ -18,6 +18,30 @@ namespace Microsoft.SqlTools.EditorServices
/// </summary>
public class ScriptFile
{
public ScriptFile(
string filePath,
string clientFilePath,
TextReader textReader,
Version SqlToolsVersion)
{
}
/// <summary>
/// Creates a new ScriptFile instance with the specified file contents.
/// </summary>
/// <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)
{
}
#if false
#region Private Fields

View File

@@ -6,9 +6,9 @@
using Microsoft.SqlTools.EditorServices.Utility;
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
namespace Microsoft.SqlTools.EditorServices
{
@@ -18,8 +18,7 @@ namespace Microsoft.SqlTools.EditorServices
/// </summary>
public class Workspace
{
#if false
#region Private Fields
#region Private Fields
private Version SqlToolsVersion;
private Dictionary<string, ScriptFile> workspaceFiles = new Dictionary<string, ScriptFile>();
@@ -93,6 +92,70 @@ namespace Microsoft.SqlTools.EditorServices
return scriptFile;
}
private string ResolveFilePath(string filePath)
{
if (!IsPathInMemory(filePath))
{
if (filePath.StartsWith(@"file://"))
{
// Client sent the path in URI format, extract the local path and trim
// any extraneous slashes
Uri fileUri = new Uri(filePath);
filePath = fileUri.LocalPath.TrimStart('/');
}
// Some clients send paths with UNIX-style slashes, replace those if necessary
filePath = filePath.Replace('/', '\\');
// Clients could specify paths with escaped space, [ and ] characters which .NET APIs
// will not handle. These paths will get appropriately escaped just before being passed
// into the SqlTools engine.
filePath = UnescapePath(filePath);
// Get the absolute file path
filePath = Path.GetFullPath(filePath);
}
Logger.Write(LogLevel.Verbose, "Resolved path: " + filePath);
return filePath;
}
internal static bool IsPathInMemory(string filePath)
{
// When viewing SqlTools files in the Git diff viewer, VS Code
// sends the contents of the file at HEAD with a URI that starts
// with 'inmemory'. Untitled files which have been marked of
// type SqlTools have a path starting with 'untitled'.
return
filePath.StartsWith("inmemory") ||
filePath.StartsWith("untitled");
}
/// <summary>
/// Unescapes any escaped [, ] or space characters. Typically use this before calling a
/// .NET API that doesn't understand PowerShell escaped chars.
/// </summary>
/// <param name="path">The path to unescape.</param>
/// <returns>The path with the ` character before [, ] and spaces removed.</returns>
public static string UnescapePath(string path)
{
if (!path.Contains("`"))
{
return path;
}
return Regex.Replace(path, @"`(?=[ \[\]])", "");
}
#endregion
#if false
#region Public Methods
/// <summary>
/// Gets a new ScriptFile instance which is identified by the given file
@@ -222,46 +285,6 @@ namespace Microsoft.SqlTools.EditorServices
}
}
private string ResolveFilePath(string filePath)
{
if (!IsPathInMemory(filePath))
{
if (filePath.StartsWith(@"file://"))
{
// Client sent the path in URI format, extract the local path and trim
// any extraneous slashes
Uri fileUri = new Uri(filePath);
filePath = fileUri.LocalPath.TrimStart('/');
}
// Some clients send paths with UNIX-style slashes, replace those if necessary
filePath = filePath.Replace('/', '\\');
// Clients could specify paths with escaped space, [ and ] characters which .NET APIs
// will not handle. These paths will get appropriately escaped just before being passed
// into the SqlTools engine.
filePath = SqlToolsContext.UnescapePath(filePath);
// Get the absolute file path
filePath = Path.GetFullPath(filePath);
}
Logger.Write(LogLevel.Verbose, "Resolved path: " + filePath);
return filePath;
}
internal static bool IsPathInMemory(string filePath)
{
// When viewing SqlTools files in the Git diff viewer, VS Code
// sends the contents of the file at HEAD with a URI that starts
// with 'inmemory'. Untitled files which have been marked of
// type SqlTools have a path starting with 'untitled'.
return
filePath.StartsWith("inmemory") ||
filePath.StartsWith("untitled");
}
private string GetBaseFilePath(string filePath)
{
if (IsPathInMemory(filePath))