mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-01-13 17:23:02 -05:00
Additional code cleanup following initial check-in.
Enable more ScriptFile code and hook in stub for error parsing.
This commit is contained in:
@@ -10,11 +10,18 @@ using System.Threading.Tasks;
|
||||
using Microsoft.SqlTools.EditorServices.Utility;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.SqlTools.EditorServices.Protocol.Server
|
||||
{
|
||||
/// <summary>
|
||||
/// SQL Tools VS Code Language Server request handler
|
||||
/// </summary>
|
||||
public class LanguageServer : LanguageServerBase
|
||||
{
|
||||
private static CancellationTokenSource existingRequestCancellation;
|
||||
|
||||
private EditorSession editorSession;
|
||||
|
||||
/// <param name="hostDetails">
|
||||
@@ -118,21 +125,20 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server
|
||||
|
||||
ScriptFile changedFile = editorSession.Workspace.GetFile(fileUri);
|
||||
|
||||
// changedFile.ApplyChange(
|
||||
// GetFileChangeDetails(
|
||||
// textChange.Range.Value,
|
||||
// textChange.Text));
|
||||
changedFile.ApplyChange(
|
||||
GetFileChangeDetails(
|
||||
textChange.Range.Value,
|
||||
textChange.Text));
|
||||
|
||||
// changedFiles.Add(changedFile);
|
||||
changedFiles.Add(changedFile);
|
||||
}
|
||||
|
||||
Logger.Write(LogLevel.Normal, msg.ToString());
|
||||
|
||||
// // TODO: Get all recently edited files in the workspace
|
||||
// this.RunScriptDiagnostics(
|
||||
// changedFiles.ToArray(),
|
||||
// editorSession,
|
||||
// eventContext);
|
||||
this.RunScriptDiagnostics(
|
||||
changedFiles.ToArray(),
|
||||
editorSession,
|
||||
eventContext);
|
||||
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
@@ -231,6 +237,214 @@ namespace Microsoft.SqlTools.EditorServices.Protocol.Server
|
||||
{
|
||||
Logger.Write(LogLevel.Normal, "HandleWorkspaceSymbolRequest");
|
||||
await Task.FromResult(true);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
// {
|
||||
// // TODO: Catch a more specific exception!
|
||||
// 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.
|
||||
// TODO: Is there a better way to do this?
|
||||
existingRequestCancellation = new CancellationTokenSource();
|
||||
Task.Factory.StartNew(
|
||||
() =>
|
||||
DelayThenInvokeDiagnostics(
|
||||
750,
|
||||
filesToAnalyze,
|
||||
editorSession,
|
||||
eventContext,
|
||||
existingRequestCancellation.Token),
|
||||
CancellationToken.None,
|
||||
TaskCreationOptions.None,
|
||||
TaskScheduler.Default);
|
||||
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
|
||||
|
||||
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.AnalysisService != null)
|
||||
// {
|
||||
// Logger.Write(LogLevel.Verbose, "Analyzing script file: " + scriptFile.FilePath);
|
||||
|
||||
// semanticMarkers =
|
||||
// editorSession.AnalysisService.GetSemanticMarkers(
|
||||
// scriptFile);
|
||||
|
||||
// Logger.Write(LogLevel.Verbose, "Analysis complete.");
|
||||
// }
|
||||
// else
|
||||
{
|
||||
// Semantic markers aren't available if the AnalysisService
|
||||
// isn't available
|
||||
semanticMarkers = new ScriptFileMarker[0];
|
||||
// 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
|
||||
// }
|
||||
// };
|
||||
}
|
||||
|
||||
await PublishScriptDiagnostics(
|
||||
scriptFile,
|
||||
semanticMarkers,
|
||||
eventContext);
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
});
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,10 +75,6 @@ namespace Microsoft.SqlTools.EditorServices
|
||||
#if false
|
||||
#region Properties
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the LanguageService instance for this session.
|
||||
/// </summary>
|
||||
|
||||
@@ -108,4 +108,3 @@ namespace Microsoft.SqlTools.EditorServices
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,14 +11,6 @@ namespace Microsoft.SqlTools.EditorServices
|
||||
/// </summary>
|
||||
public class FilePosition : BufferPosition
|
||||
{
|
||||
public FilePosition(
|
||||
ScriptFile scriptFile,
|
||||
int line,
|
||||
int column)
|
||||
: base(line, column)
|
||||
{
|
||||
}
|
||||
#if false
|
||||
#region Private Fields
|
||||
|
||||
private ScriptFile scriptFile;
|
||||
@@ -112,7 +104,7 @@ namespace Microsoft.SqlTools.EditorServices
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,8 +8,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
//using System.Management.Automation;
|
||||
//using System.Management.Automation.Language;
|
||||
|
||||
namespace Microsoft.SqlTools.EditorServices
|
||||
{
|
||||
@@ -18,34 +16,8 @@ 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
|
||||
|
||||
private Token[] scriptTokens;
|
||||
private Version SqlToolsVersion;
|
||||
|
||||
#endregion
|
||||
@@ -121,23 +93,6 @@ namespace Microsoft.SqlTools.EditorServices
|
||||
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>
|
||||
/// Gets the array of filepaths dot sourced in this ScriptFile
|
||||
/// </summary>
|
||||
@@ -502,6 +457,7 @@ namespace Microsoft.SqlTools.EditorServices
|
||||
/// </summary>
|
||||
private void ParseFileContents()
|
||||
{
|
||||
#if false
|
||||
ParseError[] parseErrors = null;
|
||||
|
||||
// First, get the updated file range
|
||||
@@ -574,9 +530,9 @@ namespace Microsoft.SqlTools.EditorServices
|
||||
//Get all dot sourced referenced files and store them
|
||||
this.ReferencedFiles =
|
||||
AstOperations.FindDotSourcedIncludes(this.ScriptAst);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,14 +3,6 @@
|
||||
// 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
|
||||
{
|
||||
/// <summary>
|
||||
@@ -59,60 +51,6 @@ namespace Microsoft.SqlTools.EditorServices
|
||||
public ScriptRegion ScriptRegion { get; set; }
|
||||
|
||||
#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.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.SqlTools.EditorServices
|
||||
{
|
||||
@@ -149,15 +150,7 @@ namespace Microsoft.SqlTools.EditorServices
|
||||
return Regex.Replace(path, @"`(?=[ \[\]])", "");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#if false
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// <summary>
|
||||
/// Gets a new ScriptFile instance which is identified by the given file
|
||||
/// path and initially contains the given buffer contents.
|
||||
/// </summary>
|
||||
@@ -211,80 +204,6 @@ namespace Microsoft.SqlTools.EditorServices
|
||||
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)
|
||||
{
|
||||
if (IsPathInMemory(filePath))
|
||||
@@ -324,7 +243,6 @@ namespace Microsoft.SqlTools.EditorServices
|
||||
return combinedPath;
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endif
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user