mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-02-16 10:58:30 -05:00
Merge branch 'dev'
This commit is contained in:
57
ServiceHost/LanguageSupport/LanguageService.cs
Normal file
57
ServiceHost/LanguageSupport/LanguageService.cs
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
//
|
||||||
|
// 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;
|
||||||
|
using Microsoft.SqlTools.EditorServices.Session;
|
||||||
|
|
||||||
|
namespace Microsoft.SqlTools.LanguageSupport
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Main class for Language Service functionality
|
||||||
|
/// </summary>
|
||||||
|
public class LanguageService
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the current SQL Tools context
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
private SqlToolsContext Context { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructor for the Language Service class
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context"></param>
|
||||||
|
public LanguageService(SqlToolsContext context)
|
||||||
|
{
|
||||||
|
this.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)
|
||||||
|
{
|
||||||
|
// the commented out snippet is an example of how to create a error marker
|
||||||
|
// semanticMarkers = new ScriptFileMarker[1];
|
||||||
|
// semanticMarkers[0] = new ScriptFileMarker()
|
||||||
|
// {
|
||||||
|
// Message = "Error message",
|
||||||
|
// Level = ScriptFileMarkerLevel.Error,
|
||||||
|
// ScriptRegion = new ScriptRegion()
|
||||||
|
// {
|
||||||
|
// File = scriptFile.FilePath,
|
||||||
|
// StartLineNumber = 2,
|
||||||
|
// StartColumnNumber = 2,
|
||||||
|
// StartOffset = 0,
|
||||||
|
// EndLineNumber = 4,
|
||||||
|
// EndColumnNumber = 10,
|
||||||
|
// EndOffset = 0
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
return new ScriptFileMarker[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,7 +18,9 @@ namespace Microsoft.SqlTools.ServiceHost
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
static void Main(string[] args)
|
static void Main(string[] args)
|
||||||
{
|
{
|
||||||
Logger.Initialize();
|
// turn on Verbose logging during early development
|
||||||
|
// we need to switch to Normal when preparing for public preview
|
||||||
|
Logger.Initialize(minimumLogLevel: LogLevel.Verbose);
|
||||||
Logger.Write(LogLevel.Normal, "Starting SQL Tools Service Host");
|
Logger.Write(LogLevel.Normal, "Starting SQL Tools Service Host");
|
||||||
|
|
||||||
const string hostName = "SQL Tools Service Host";
|
const string hostName = "SQL Tools Service Host";
|
||||||
|
|||||||
@@ -10,11 +10,21 @@ using System.Threading.Tasks;
|
|||||||
using Microsoft.SqlTools.EditorServices.Utility;
|
using Microsoft.SqlTools.EditorServices.Utility;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Linq;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Microsoft.SqlTools.EditorServices.Protocol.Server
|
namespace Microsoft.SqlTools.EditorServices.Protocol.Server
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// SQL Tools VS Code Language Server request handler
|
||||||
|
/// </summary>
|
||||||
public class LanguageServer : LanguageServerBase
|
public class LanguageServer : LanguageServerBase
|
||||||
{
|
{
|
||||||
|
private static CancellationTokenSource existingRequestCancellation;
|
||||||
|
|
||||||
|
private LanguageServerSettings currentSettings = new LanguageServerSettings();
|
||||||
|
|
||||||
private EditorSession editorSession;
|
private EditorSession editorSession;
|
||||||
|
|
||||||
/// <param name="hostDetails">
|
/// <param name="hostDetails">
|
||||||
@@ -27,6 +37,9 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server
|
|||||||
this.editorSession.StartSession(hostDetails, profilePaths);
|
this.editorSession.StartSession(hostDetails, profilePaths);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialize the VS Code request/response callbacks
|
||||||
|
/// </summary>
|
||||||
protected override void Initialize()
|
protected override void Initialize()
|
||||||
{
|
{
|
||||||
// Register all supported message types
|
// Register all supported message types
|
||||||
@@ -47,6 +60,9 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server
|
|||||||
this.SetRequestHandler(WorkspaceSymbolRequest.Type, this.HandleWorkspaceSymbolRequest);
|
this.SetRequestHandler(WorkspaceSymbolRequest.Type, this.HandleWorkspaceSymbolRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles the shutdown event for the Language Server
|
||||||
|
/// </summary>
|
||||||
protected override async Task Shutdown()
|
protected override async Task Shutdown()
|
||||||
{
|
{
|
||||||
Logger.Write(LogLevel.Normal, "Language service is shutting down...");
|
Logger.Write(LogLevel.Normal, "Language service is shutting down...");
|
||||||
@@ -60,14 +76,20 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server
|
|||||||
await Task.FromResult(true);
|
await Task.FromResult(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles the initialization request
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="initializeParams"></param>
|
||||||
|
/// <param name="requestContext"></param>
|
||||||
|
/// <returns></returns>
|
||||||
protected async Task HandleInitializeRequest(
|
protected async Task HandleInitializeRequest(
|
||||||
InitializeRequest initializeParams,
|
InitializeRequest initializeParams,
|
||||||
RequestContext<InitializeResult> requestContext)
|
RequestContext<InitializeResult> requestContext)
|
||||||
{
|
{
|
||||||
Logger.Write(LogLevel.Normal, "HandleDidChangeTextDocumentNotification");
|
Logger.Write(LogLevel.Verbose, "HandleDidChangeTextDocumentNotification");
|
||||||
|
|
||||||
// Grab the workspace path from the parameters
|
// Grab the workspace path from the parameters
|
||||||
//editorSession.Workspace.WorkspacePath = initializeParams.RootPath;
|
editorSession.Workspace.WorkspacePath = initializeParams.RootPath;
|
||||||
|
|
||||||
await requestContext.SendResult(
|
await requestContext.SendResult(
|
||||||
new InitializeResult
|
new InitializeResult
|
||||||
@@ -118,21 +140,20 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server
|
|||||||
|
|
||||||
ScriptFile changedFile = editorSession.Workspace.GetFile(fileUri);
|
ScriptFile changedFile = editorSession.Workspace.GetFile(fileUri);
|
||||||
|
|
||||||
// changedFile.ApplyChange(
|
changedFile.ApplyChange(
|
||||||
// GetFileChangeDetails(
|
GetFileChangeDetails(
|
||||||
// textChange.Range.Value,
|
textChange.Range.Value,
|
||||||
// textChange.Text));
|
textChange.Text));
|
||||||
|
|
||||||
// changedFiles.Add(changedFile);
|
changedFiles.Add(changedFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.Write(LogLevel.Normal, msg.ToString());
|
Logger.Write(LogLevel.Verbose, msg.ToString());
|
||||||
|
|
||||||
// // TODO: Get all recently edited files in the workspace
|
this.RunScriptDiagnostics(
|
||||||
// this.RunScriptDiagnostics(
|
changedFiles.ToArray(),
|
||||||
// changedFiles.ToArray(),
|
editorSession,
|
||||||
// editorSession,
|
eventContext);
|
||||||
// eventContext);
|
|
||||||
|
|
||||||
return Task.FromResult(true);
|
return Task.FromResult(true);
|
||||||
}
|
}
|
||||||
@@ -141,7 +162,7 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server
|
|||||||
DidOpenTextDocumentNotification openParams,
|
DidOpenTextDocumentNotification openParams,
|
||||||
EventContext eventContext)
|
EventContext eventContext)
|
||||||
{
|
{
|
||||||
Logger.Write(LogLevel.Normal, "HandleDidOpenTextDocumentNotification");
|
Logger.Write(LogLevel.Verbose, "HandleDidOpenTextDocumentNotification");
|
||||||
return Task.FromResult(true);
|
return Task.FromResult(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,15 +170,57 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server
|
|||||||
TextDocumentIdentifier closeParams,
|
TextDocumentIdentifier closeParams,
|
||||||
EventContext eventContext)
|
EventContext eventContext)
|
||||||
{
|
{
|
||||||
Logger.Write(LogLevel.Normal, "HandleDidCloseTextDocumentNotification");
|
Logger.Write(LogLevel.Verbose, "HandleDidCloseTextDocumentNotification");
|
||||||
return Task.FromResult(true);
|
return Task.FromResult(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles the configuration change event
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="configChangeParams"></param>
|
||||||
|
/// <param name="eventContext"></param>
|
||||||
protected async Task HandleDidChangeConfigurationNotification(
|
protected async Task HandleDidChangeConfigurationNotification(
|
||||||
DidChangeConfigurationParams<LanguageServerSettingsWrapper> configChangeParams,
|
DidChangeConfigurationParams<LanguageServerSettingsWrapper> configChangeParams,
|
||||||
EventContext eventContext)
|
EventContext eventContext)
|
||||||
{
|
{
|
||||||
Logger.Write(LogLevel.Normal, "HandleDidChangeConfigurationNotification");
|
Logger.Write(LogLevel.Verbose, "HandleDidChangeConfigurationNotification");
|
||||||
|
|
||||||
|
bool oldLoadProfiles = this.currentSettings.EnableProfileLoading;
|
||||||
|
bool oldScriptAnalysisEnabled =
|
||||||
|
this.currentSettings.ScriptAnalysis.Enable.HasValue;
|
||||||
|
string oldScriptAnalysisSettingsPath =
|
||||||
|
this.currentSettings.ScriptAnalysis.SettingsPath;
|
||||||
|
|
||||||
|
this.currentSettings.Update(
|
||||||
|
configChangeParams.Settings.SqlTools,
|
||||||
|
this.editorSession.Workspace.WorkspacePath);
|
||||||
|
|
||||||
|
// If script analysis settings have changed we need to clear & possibly update the current diagnostic records.
|
||||||
|
if ((oldScriptAnalysisEnabled != this.currentSettings.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 (!this.currentSettings.ScriptAnalysis.Enable.Value)
|
||||||
|
{
|
||||||
|
ScriptFileMarker[] emptyAnalysisDiagnostics = new ScriptFileMarker[0];
|
||||||
|
|
||||||
|
foreach (var scriptFile in editorSession.Workspace.GetOpenedFiles())
|
||||||
|
{
|
||||||
|
await PublishScriptDiagnostics(
|
||||||
|
scriptFile,
|
||||||
|
emptyAnalysisDiagnostics,
|
||||||
|
eventContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await this.RunScriptDiagnostics(
|
||||||
|
this.editorSession.Workspace.GetOpenedFiles(),
|
||||||
|
this.editorSession,
|
||||||
|
eventContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await Task.FromResult(true);
|
await Task.FromResult(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,7 +228,7 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server
|
|||||||
TextDocumentPosition textDocumentPosition,
|
TextDocumentPosition textDocumentPosition,
|
||||||
RequestContext<Location[]> requestContext)
|
RequestContext<Location[]> requestContext)
|
||||||
{
|
{
|
||||||
Logger.Write(LogLevel.Normal, "HandleDefinitionRequest");
|
Logger.Write(LogLevel.Verbose, "HandleDefinitionRequest");
|
||||||
await Task.FromResult(true);
|
await Task.FromResult(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,7 +236,7 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server
|
|||||||
ReferencesParams referencesParams,
|
ReferencesParams referencesParams,
|
||||||
RequestContext<Location[]> requestContext)
|
RequestContext<Location[]> requestContext)
|
||||||
{
|
{
|
||||||
Logger.Write(LogLevel.Normal, "HandleReferencesRequest");
|
Logger.Write(LogLevel.Verbose, "HandleReferencesRequest");
|
||||||
await Task.FromResult(true);
|
await Task.FromResult(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,7 +244,7 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server
|
|||||||
TextDocumentPosition textDocumentPosition,
|
TextDocumentPosition textDocumentPosition,
|
||||||
RequestContext<CompletionItem[]> requestContext)
|
RequestContext<CompletionItem[]> requestContext)
|
||||||
{
|
{
|
||||||
Logger.Write(LogLevel.Normal, "HandleCompletionRequest");
|
Logger.Write(LogLevel.Verbose, "HandleCompletionRequest");
|
||||||
await Task.FromResult(true);
|
await Task.FromResult(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,7 +252,7 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server
|
|||||||
CompletionItem completionItem,
|
CompletionItem completionItem,
|
||||||
RequestContext<CompletionItem> requestContext)
|
RequestContext<CompletionItem> requestContext)
|
||||||
{
|
{
|
||||||
Logger.Write(LogLevel.Normal, "HandleCompletionResolveRequest");
|
Logger.Write(LogLevel.Verbose, "HandleCompletionResolveRequest");
|
||||||
await Task.FromResult(true);
|
await Task.FromResult(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,7 +260,7 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server
|
|||||||
TextDocumentPosition textDocumentPosition,
|
TextDocumentPosition textDocumentPosition,
|
||||||
RequestContext<SignatureHelp> requestContext)
|
RequestContext<SignatureHelp> requestContext)
|
||||||
{
|
{
|
||||||
Logger.Write(LogLevel.Normal, "HandleSignatureHelpRequest");
|
Logger.Write(LogLevel.Verbose, "HandleSignatureHelpRequest");
|
||||||
await Task.FromResult(true);
|
await Task.FromResult(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,7 +268,7 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server
|
|||||||
TextDocumentPosition textDocumentPosition,
|
TextDocumentPosition textDocumentPosition,
|
||||||
RequestContext<DocumentHighlight[]> requestContext)
|
RequestContext<DocumentHighlight[]> requestContext)
|
||||||
{
|
{
|
||||||
Logger.Write(LogLevel.Normal, "HandleDocumentHighlightRequest");
|
Logger.Write(LogLevel.Verbose, "HandleDocumentHighlightRequest");
|
||||||
await Task.FromResult(true);
|
await Task.FromResult(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,7 +276,7 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server
|
|||||||
TextDocumentPosition textDocumentPosition,
|
TextDocumentPosition textDocumentPosition,
|
||||||
RequestContext<Hover> requestContext)
|
RequestContext<Hover> requestContext)
|
||||||
{
|
{
|
||||||
Logger.Write(LogLevel.Normal, "HandleHoverRequest");
|
Logger.Write(LogLevel.Verbose, "HandleHoverRequest");
|
||||||
await Task.FromResult(true);
|
await Task.FromResult(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,7 +284,7 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server
|
|||||||
TextDocumentIdentifier textDocumentIdentifier,
|
TextDocumentIdentifier textDocumentIdentifier,
|
||||||
RequestContext<SymbolInformation[]> requestContext)
|
RequestContext<SymbolInformation[]> requestContext)
|
||||||
{
|
{
|
||||||
Logger.Write(LogLevel.Normal, "HandleDocumentSymbolRequest");
|
Logger.Write(LogLevel.Verbose, "HandleDocumentSymbolRequest");
|
||||||
await Task.FromResult(true);
|
await Task.FromResult(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,8 +292,226 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server
|
|||||||
WorkspaceSymbolParams workspaceSymbolParams,
|
WorkspaceSymbolParams workspaceSymbolParams,
|
||||||
RequestContext<SymbolInformation[]> requestContext)
|
RequestContext<SymbolInformation[]> requestContext)
|
||||||
{
|
{
|
||||||
Logger.Write(LogLevel.Normal, "HandleWorkspaceSymbolRequest");
|
Logger.Write(LogLevel.Verbose, "HandleWorkspaceSymbolRequest");
|
||||||
await Task.FromResult(true);
|
await Task.FromResult(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Runs script diagnostics on changed files
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filesToAnalyze"></param>
|
||||||
|
/// <param name="editorSession"></param>
|
||||||
|
/// <param name="eventContext"></param>
|
||||||
|
private Task RunScriptDiagnostics(
|
||||||
|
ScriptFile[] filesToAnalyze,
|
||||||
|
EditorSession editorSession,
|
||||||
|
EventContext eventContext)
|
||||||
|
{
|
||||||
|
if (!this.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,
|
||||||
|
editorSession,
|
||||||
|
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="editorSession"></param>
|
||||||
|
/// <param name="eventContext"></param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
private static async Task DelayThenInvokeDiagnostics(
|
||||||
|
int delayMilliseconds,
|
||||||
|
ScriptFile[] filesToAnalyze,
|
||||||
|
EditorSession editorSession,
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
ScriptFileMarker[] semanticMarkers = null;
|
||||||
|
if (editorSession.LanguageService != null)
|
||||||
|
{
|
||||||
|
Logger.Write(LogLevel.Verbose, "Analyzing script file: " + scriptFile.FilePath);
|
||||||
|
semanticMarkers = editorSession.LanguageService.GetSemanticMarkers(scriptFile);
|
||||||
|
Logger.Write(LogLevel.Verbose, "Analysis complete.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Semantic markers aren't available if the AnalysisService
|
||||||
|
// isn't available
|
||||||
|
semanticMarkers = new ScriptFileMarker[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using Microsoft.SqlTools.EditorServices.Session;
|
using Microsoft.SqlTools.EditorServices.Session;
|
||||||
|
using Microsoft.SqlTools.LanguageSupport;
|
||||||
|
|
||||||
namespace Microsoft.SqlTools.EditorServices
|
namespace Microsoft.SqlTools.EditorServices
|
||||||
{
|
{
|
||||||
@@ -21,6 +22,12 @@ namespace Microsoft.SqlTools.EditorServices
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public Workspace Workspace { get; private set; }
|
public Workspace Workspace { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Language Service
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public LanguageService LanguageService { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the SqlToolsContext instance for this session.
|
/// Gets the SqlToolsContext instance for this session.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -30,84 +37,6 @@ namespace Microsoft.SqlTools.EditorServices
|
|||||||
|
|
||||||
#region Public Methods
|
#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>
|
|
||||||
public LanguageService LanguageService { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the AnalysisService instance for this session.
|
|
||||||
/// </summary>
|
|
||||||
public AnalysisService AnalysisService { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the DebugService instance for this session.
|
|
||||||
/// </summary>
|
|
||||||
public DebugService DebugService { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the ConsoleService instance for this session.
|
|
||||||
/// </summary>
|
|
||||||
public ConsoleService ConsoleService { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the ExtensionService instance for this session.
|
|
||||||
/// </summary>
|
|
||||||
public ExtensionService ExtensionService { get; private set; }
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Public Methods
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Starts the session using the provided IConsoleHost implementation
|
/// Starts the session using the provided IConsoleHost implementation
|
||||||
/// for the ConsoleService.
|
/// for the ConsoleService.
|
||||||
@@ -123,59 +52,11 @@ namespace Microsoft.SqlTools.EditorServices
|
|||||||
// Initialize all services
|
// Initialize all services
|
||||||
this.SqlToolsContext = new SqlToolsContext(hostDetails, profilePaths);
|
this.SqlToolsContext = new SqlToolsContext(hostDetails, profilePaths);
|
||||||
this.LanguageService = new LanguageService(this.SqlToolsContext);
|
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
|
// Create a workspace to contain open files
|
||||||
this.Workspace = new Workspace(this.SqlToolsContext.SqlToolsVersion);
|
this.Workspace = new Workspace(this.SqlToolsContext.SqlToolsVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Restarts the AnalysisService so it can be configured with a new settings file.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="settingsPath">Path to the settings file.</param>
|
|
||||||
public void RestartAnalysisService(string settingsPath)
|
|
||||||
{
|
|
||||||
this.AnalysisService?.Dispose();
|
|
||||||
InstantiateAnalysisService(settingsPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void InstantiateAnalysisService(string settingsPath = null)
|
|
||||||
{
|
|
||||||
// Only enable the AnalysisService if the machine has SqlTools
|
|
||||||
// v5 installed. Script Analyzer works on earlier SqlTools
|
|
||||||
// versions but our hard dependency on their binaries complicates
|
|
||||||
// the deployment and assembly loading since we would have to
|
|
||||||
// conditionally load the binaries for v3/v4 support. This problem
|
|
||||||
// will be solved in the future by using Script Analyzer as a
|
|
||||||
// module rather than an assembly dependency.
|
|
||||||
if (this.SqlToolsContext.SqlToolsVersion.Major >= 5)
|
|
||||||
{
|
|
||||||
// AnalysisService will throw FileNotFoundException if
|
|
||||||
// Script Analyzer binaries are not included.
|
|
||||||
try
|
|
||||||
{
|
|
||||||
this.AnalysisService = new AnalysisService(this.SqlToolsContext.ConsoleHost, settingsPath);
|
|
||||||
}
|
|
||||||
catch (FileNotFoundException)
|
|
||||||
{
|
|
||||||
Logger.Write(
|
|
||||||
LogLevel.Warning,
|
|
||||||
"Script Analyzer binaries not found, AnalysisService will be disabled.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Logger.Write(
|
|
||||||
LogLevel.Normal,
|
|
||||||
"Script Analyzer cannot be loaded due to unsupported SqlTools version " +
|
|
||||||
this.SqlToolsContext.SqlToolsVersion.ToString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region IDisposable Implementation
|
#region IDisposable Implementation
|
||||||
@@ -185,21 +66,10 @@ namespace Microsoft.SqlTools.EditorServices
|
|||||||
/// services used in this session.
|
/// services used in this session.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
if (this.AnalysisService != null)
|
|
||||||
{
|
|
||||||
this.AnalysisService.Dispose();
|
|
||||||
this.AnalysisService = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.SqlToolsContext != null)
|
|
||||||
{
|
|
||||||
this.SqlToolsContext.Dispose();
|
|
||||||
this.SqlToolsContext = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,4 +108,3 @@ namespace Microsoft.SqlTools.EditorServices
|
|||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,14 +11,6 @@ namespace Microsoft.SqlTools.EditorServices
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class FilePosition : BufferPosition
|
public class FilePosition : BufferPosition
|
||||||
{
|
{
|
||||||
public FilePosition(
|
|
||||||
ScriptFile scriptFile,
|
|
||||||
int line,
|
|
||||||
int column)
|
|
||||||
: base(line, column)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
#if false
|
|
||||||
#region Private Fields
|
#region Private Fields
|
||||||
|
|
||||||
private ScriptFile scriptFile;
|
private ScriptFile scriptFile;
|
||||||
@@ -112,7 +104,7 @@ namespace Microsoft.SqlTools.EditorServices
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,8 +8,6 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
//using System.Management.Automation;
|
|
||||||
//using System.Management.Automation.Language;
|
|
||||||
|
|
||||||
namespace Microsoft.SqlTools.EditorServices
|
namespace Microsoft.SqlTools.EditorServices
|
||||||
{
|
{
|
||||||
@@ -18,34 +16,8 @@ namespace Microsoft.SqlTools.EditorServices
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class ScriptFile
|
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
|
#region Private Fields
|
||||||
|
|
||||||
private Token[] scriptTokens;
|
|
||||||
private Version SqlToolsVersion;
|
private Version SqlToolsVersion;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@@ -121,23 +93,6 @@ namespace Microsoft.SqlTools.EditorServices
|
|||||||
private set;
|
private set;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the ScriptBlockAst representing the parsed script contents.
|
|
||||||
/// </summary>
|
|
||||||
public ScriptBlockAst ScriptAst
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the array of Tokens representing the parsed script contents.
|
|
||||||
/// </summary>
|
|
||||||
public Token[] ScriptTokens
|
|
||||||
{
|
|
||||||
get { return this.scriptTokens; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the array of filepaths dot sourced in this ScriptFile
|
/// Gets the array of filepaths dot sourced in this ScriptFile
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -502,6 +457,7 @@ namespace Microsoft.SqlTools.EditorServices
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void ParseFileContents()
|
private void ParseFileContents()
|
||||||
{
|
{
|
||||||
|
#if false
|
||||||
ParseError[] parseErrors = null;
|
ParseError[] parseErrors = null;
|
||||||
|
|
||||||
// First, get the updated file range
|
// First, get the updated file range
|
||||||
@@ -574,9 +530,9 @@ namespace Microsoft.SqlTools.EditorServices
|
|||||||
//Get all dot sourced referenced files and store them
|
//Get all dot sourced referenced files and store them
|
||||||
this.ReferencedFiles =
|
this.ReferencedFiles =
|
||||||
AstOperations.FindDotSourcedIncludes(this.ScriptAst);
|
AstOperations.FindDotSourcedIncludes(this.ScriptAst);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,14 +3,6 @@
|
|||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
// 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.Management.Automation.Language;
|
|
||||||
|
|
||||||
#if ScriptAnalyzer
|
|
||||||
using Microsoft.Windows.SqlTools.ScriptAnalyzer.Generic;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace Microsoft.SqlTools.EditorServices
|
namespace Microsoft.SqlTools.EditorServices
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -59,60 +51,6 @@ namespace Microsoft.SqlTools.EditorServices
|
|||||||
public ScriptRegion ScriptRegion { get; set; }
|
public ScriptRegion ScriptRegion { get; set; }
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Public Methods
|
|
||||||
|
|
||||||
#if false
|
|
||||||
internal static ScriptFileMarker FromParseError(
|
|
||||||
ParseError parseError)
|
|
||||||
{
|
|
||||||
Validate.IsNotNull("parseError", parseError);
|
|
||||||
|
|
||||||
return new ScriptFileMarker
|
|
||||||
{
|
|
||||||
Message = parseError.Message,
|
|
||||||
Level = ScriptFileMarkerLevel.Error,
|
|
||||||
ScriptRegion = ScriptRegion.Create(parseError.Extent)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if ScriptAnalyzer
|
|
||||||
internal static ScriptFileMarker FromDiagnosticRecord(
|
|
||||||
DiagnosticRecord diagnosticRecord)
|
|
||||||
{
|
|
||||||
Validate.IsNotNull("diagnosticRecord", diagnosticRecord);
|
|
||||||
|
|
||||||
return new ScriptFileMarker
|
|
||||||
{
|
|
||||||
Message = diagnosticRecord.Message,
|
|
||||||
Level = GetMarkerLevelFromDiagnosticSeverity(diagnosticRecord.Severity),
|
|
||||||
ScriptRegion = ScriptRegion.Create(diagnosticRecord.Extent)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ScriptFileMarkerLevel GetMarkerLevelFromDiagnosticSeverity(
|
|
||||||
DiagnosticSeverity diagnosticSeverity)
|
|
||||||
{
|
|
||||||
switch (diagnosticSeverity)
|
|
||||||
{
|
|
||||||
case DiagnosticSeverity.Information:
|
|
||||||
return ScriptFileMarkerLevel.Information;
|
|
||||||
case DiagnosticSeverity.Warning:
|
|
||||||
return ScriptFileMarkerLevel.Warning;
|
|
||||||
case DiagnosticSeverity.Error:
|
|
||||||
return ScriptFileMarkerLevel.Error;
|
|
||||||
default:
|
|
||||||
throw new ArgumentException(
|
|
||||||
string.Format(
|
|
||||||
"The provided DiagnosticSeverity value '{0}' is unknown.",
|
|
||||||
diagnosticSeverity),
|
|
||||||
"diagnosticSeverity");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ using System.Collections.Generic;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Microsoft.SqlTools.EditorServices
|
namespace Microsoft.SqlTools.EditorServices
|
||||||
{
|
{
|
||||||
@@ -149,15 +150,7 @@ namespace Microsoft.SqlTools.EditorServices
|
|||||||
return Regex.Replace(path, @"`(?=[ \[\]])", "");
|
return Regex.Replace(path, @"`(?=[ \[\]])", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
/// <summary>
|
||||||
|
|
||||||
#if false
|
|
||||||
|
|
||||||
|
|
||||||
#region Public Methods
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a new ScriptFile instance which is identified by the given file
|
/// Gets a new ScriptFile instance which is identified by the given file
|
||||||
/// path and initially contains the given buffer contents.
|
/// path and initially contains the given buffer contents.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -211,80 +204,6 @@ namespace Microsoft.SqlTools.EditorServices
|
|||||||
this.workspaceFiles.Remove(scriptFile.Id);
|
this.workspaceFiles.Remove(scriptFile.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets all file references by recursively searching
|
|
||||||
/// through referenced files in a scriptfile
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="scriptFile">Contains the details and contents of an open script file</param>
|
|
||||||
/// <returns>A scriptfile array where the first file
|
|
||||||
/// in the array is the "root file" of the search</returns>
|
|
||||||
public ScriptFile[] ExpandScriptReferences(ScriptFile scriptFile)
|
|
||||||
{
|
|
||||||
Dictionary<string, ScriptFile> referencedScriptFiles = new Dictionary<string, ScriptFile>();
|
|
||||||
List<ScriptFile> expandedReferences = new List<ScriptFile>();
|
|
||||||
|
|
||||||
// add original file so it's not searched for, then find all file references
|
|
||||||
referencedScriptFiles.Add(scriptFile.Id, scriptFile);
|
|
||||||
RecursivelyFindReferences(scriptFile, referencedScriptFiles);
|
|
||||||
|
|
||||||
// remove original file from referened file and add it as the first element of the
|
|
||||||
// expanded referenced list to maintain order so the original file is always first in the list
|
|
||||||
referencedScriptFiles.Remove(scriptFile.Id);
|
|
||||||
expandedReferences.Add(scriptFile);
|
|
||||||
|
|
||||||
if (referencedScriptFiles.Count > 0)
|
|
||||||
{
|
|
||||||
expandedReferences.AddRange(referencedScriptFiles.Values);
|
|
||||||
}
|
|
||||||
|
|
||||||
return expandedReferences.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Private Methods
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Recusrively searches through referencedFiles in scriptFiles
|
|
||||||
/// and builds a Dictonary of the file references
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="scriptFile">Details an contents of "root" script file</param>
|
|
||||||
/// <param name="referencedScriptFiles">A Dictionary of referenced script files</param>
|
|
||||||
private void RecursivelyFindReferences(
|
|
||||||
ScriptFile scriptFile,
|
|
||||||
Dictionary<string, ScriptFile> referencedScriptFiles)
|
|
||||||
{
|
|
||||||
// Get the base path of the current script for use in resolving relative paths
|
|
||||||
string baseFilePath =
|
|
||||||
GetBaseFilePath(
|
|
||||||
scriptFile.FilePath);
|
|
||||||
|
|
||||||
ScriptFile referencedFile;
|
|
||||||
foreach (string referencedFileName in scriptFile.ReferencedFiles)
|
|
||||||
{
|
|
||||||
string resolvedScriptPath =
|
|
||||||
this.ResolveRelativeScriptPath(
|
|
||||||
baseFilePath,
|
|
||||||
referencedFileName);
|
|
||||||
|
|
||||||
// Make sure file exists before trying to get the file
|
|
||||||
if (File.Exists(resolvedScriptPath))
|
|
||||||
{
|
|
||||||
// Get the referenced file if it's not already in referencedScriptFiles
|
|
||||||
referencedFile = this.GetFile(resolvedScriptPath);
|
|
||||||
|
|
||||||
// Normalize the resolved script path and add it to the
|
|
||||||
// referenced files list if it isn't there already
|
|
||||||
resolvedScriptPath = resolvedScriptPath.ToLower();
|
|
||||||
if (!referencedScriptFiles.ContainsKey(resolvedScriptPath))
|
|
||||||
{
|
|
||||||
referencedScriptFiles.Add(resolvedScriptPath, referencedFile);
|
|
||||||
RecursivelyFindReferences(referencedFile, referencedScriptFiles);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetBaseFilePath(string filePath)
|
private string GetBaseFilePath(string filePath)
|
||||||
{
|
{
|
||||||
if (IsPathInMemory(filePath))
|
if (IsPathInMemory(filePath))
|
||||||
@@ -324,7 +243,6 @@ namespace Microsoft.SqlTools.EditorServices
|
|||||||
return combinedPath;
|
return combinedPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user