/// <summary> /// Handle the file configuration change notification /// </summary> /// <param name="newSettings"></param> /// <param name="oldSettings"></param> /// <param name="eventContext"></param> public async Task HandleDidChangeConfigurationNotification( SqlToolsSettings newSettings, SqlToolsSettings oldSettings, EventContext eventContext) { bool oldEnableIntelliSense = oldSettings.SqlTools.IntelliSense.EnableIntellisense; bool?oldEnableDiagnostics = oldSettings.SqlTools.IntelliSense.EnableErrorChecking; // update the current settings to reflect any changes CurrentSettings.Update(newSettings); // if script analysis settings have changed we need to clear the current diagnostic markers if (oldEnableIntelliSense != newSettings.SqlTools.IntelliSense.EnableIntellisense || oldEnableDiagnostics != newSettings.SqlTools.IntelliSense.EnableErrorChecking) { // if the user just turned off diagnostics then send an event to clear the error markers if (!newSettings.IsDiagnositicsEnabled) { ScriptFileMarker[] emptyAnalysisDiagnostics = new ScriptFileMarker[0]; foreach (var scriptFile in WorkspaceService <SqlToolsSettings> .Instance.Workspace.GetOpenedFiles()) { await DiagnosticsHelper.PublishScriptDiagnostics(scriptFile, emptyAnalysisDiagnostics, eventContext); } } // otherwise rerun diagnostic analysis on all opened SQL files else { await this.RunScriptDiagnostics(CurrentWorkspace.GetOpenedFiles(), eventContext); } } }
private void PublishScriptDiagnostics(ScriptFile scriptFile, IReadOnlyList <ScriptFileMarker> markers) { var diagnostics = new Diagnostic[markers.Count]; CorrectionTableEntry fileCorrections = _mostRecentCorrectionsByFile.GetOrAdd( scriptFile, CorrectionTableEntry.CreateForFile); fileCorrections.Corrections.Clear(); for (int i = 0; i < markers.Count; i++) { ScriptFileMarker marker = markers[i]; Diagnostic diagnostic = GetDiagnosticFromMarker(marker); if (marker.Correction != null) { string diagnosticId = GetUniqueIdFromDiagnostic(diagnostic); fileCorrections.Corrections[diagnosticId] = marker.Correction; } diagnostics[i] = diagnostic; } _languageServer.TextDocument.PublishDiagnostics(new PublishDiagnosticsParams { Uri = scriptFile.DocumentUri, Diagnostics = new Container <Diagnostic>(diagnostics) }); }
protected async Task HandleDidChangeConfigurationNotification( DidChangeConfigurationParams <SettingsWrapper> configChangeParams, EventContext eventContext) { bool oldScriptAnalysisEnabled = this.currentSettings.ScriptAnalysis.Enable.HasValue; this.currentSettings.Update( configChangeParams.Settings.Powershell); if (oldScriptAnalysisEnabled != this.currentSettings.ScriptAnalysis.Enable) { // If the user just turned off script analysis, 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); } } } }
private async Task <ScriptFileMarker[]> GetSemanticMarkersFromCommandAsync(PSCommand command, Runspace runspace) { PowerShellResult result = await InvokePowerShellAsync(command, runspace).ConfigureAwait(false); IReadOnlyCollection <PSObject> diagnosticResults = result?.Output ?? s_emptyDiagnosticResult; _logger.LogDebug(String.Format("Found {0} violations", diagnosticResults.Count)); var scriptMarkers = new ScriptFileMarker[diagnosticResults.Count]; int i = 0; foreach (PSObject diagnostic in diagnosticResults) { // scriptMarkers[i] = ScriptFileMarker.FromDiagnosticRecord(diagnostic); scriptMarkers[i] = ScriptFileMarker.FromUpgradePlan(diagnostic); if (scriptMarkers[i].RuleName != "ReadyToUpgradeCmdletParameter") { i++; } } Array.Resize(ref scriptMarkers, i); return(scriptMarkers); }
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]; } var allMarkers = scriptFile.SyntaxMarkers.Concat(semanticMarkers); await PublishScriptDiagnostics( scriptFile, semanticMarkers, eventContext); } }
private async Task <ScriptFileMarker[]> GetSemanticMarkersFromCommandAsync(PSCommand command) { PowerShellResult result = await InvokePowerShellAsync(command).ConfigureAwait(false); IReadOnlyCollection <PSObject> diagnosticResults = result?.Output ?? s_emptyDiagnosticResult; _logger.LogDebug(String.Format("Found {0} violations", diagnosticResults.Count)); var scriptMarkers = new ScriptFileMarker[diagnosticResults.Count]; int i = 0; foreach (PSObject diagnostic in diagnosticResults) { scriptMarkers[i] = ScriptFileMarker.FromDiagnosticRecord(diagnostic); i++; } return(scriptMarkers); }
public void GetDiagnosticFromMarkerTest() { var scriptFileMarker = new ScriptFileMarker() { Message = "Message", Level = ScriptFileMarkerLevel.Error, ScriptRegion = new ScriptRegion() { File = "file://nofile.sql", StartLineNumber = 1, StartColumnNumber = 1, StartOffset = 0, EndLineNumber = 1, EndColumnNumber = 1, EndOffset = 0 } }; var diagnostic = DiagnosticsHelper.GetDiagnosticFromMarker(scriptFileMarker); Assert.Equal(diagnostic.Message, scriptFileMarker.Message); }
/// <summary> /// Convert a ScriptFileMarker to a Diagnostic that is Language Service compatible /// </summary> /// <param name="scriptFileMarker"></param> /// <returns></returns> internal static Diagnostic GetDiagnosticFromMarker(ScriptFileMarker scriptFileMarker) { return(new Diagnostic { Severity = MapDiagnosticSeverity(scriptFileMarker.Level), Message = scriptFileMarker.Message, Range = new Range { 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> /// Convert a ScriptFileMarker to a Diagnostic that is Language Service compatible /// </summary> /// <param name="scriptFileMarker"></param> /// <returns></returns> internal static Diagnostic GetDiagnosticFromMarker(ScriptFileMarker scriptFileMarker) { return(new Diagnostic { Severity = MapDiagnosticSeverity(scriptFileMarker.Level), Message = scriptFileMarker.Message, Range = new Microsoft.SqlTools.ServiceLayer.Workspace.Contracts.Range { 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> /// Parses the given script to provide message, warning, error. /// </summary> /// <param name="scriptToParse">Script that will be parsed</param> /// <param name="telemetryManager">Used to emit telemetry events</param> /// <returns></returns> public static IList <ScriptFileMarker> CodeSense(string scriptToParse) { if (scriptToParse == null) { return(EmptyCodeSenseItemList); } int CurrentScriptlength = scriptToParse.Length; if (CurrentScriptlength > maxStringLength) { ScriptFileMarker maxStringLengthCodeSenseItem = new ScriptFileMarker { Level = ScriptFileMarkerLevel.Error, Message = SR.ScriptTooLarge(maxStringLength, CurrentScriptlength), ScriptRegion = new ScriptRegion { // underline first row in the text StartLineNumber = 1, StartColumnNumber = 1, EndLineNumber = 2, EndColumnNumber = 1 } }; return(new ScriptFileMarker[] { maxStringLengthCodeSenseItem }); } TSqlFragment rootFragment = GetAbstractSyntaxTree(scriptToParse); TsqlMultiVisitor multiVisitor = new TsqlMultiVisitor(isCodeSenseRequest: true); // Use the vistor pattern to examine the parse tree rootFragment.AcceptChildren(multiVisitor); // Now walk the tree if (multiVisitor.CodeSenseErrors != null && multiVisitor.CodeSenseErrors.Count != 0) { multiVisitor.CodeSenseMessages.AddRange(multiVisitor.CodeSenseErrors); } return(multiVisitor.CodeSenseMessages); }
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 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 async static Task PublishScriptDiagnostics( ScriptFile scriptFile, ScriptFileMarker[] semanticMarkers, EventContext eventContext) { var allMarkers = scriptFile.SyntaxMarkers.Concat(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() }); }
protected async Task HandleDidChangeConfigurationNotification( DidChangeConfigurationParams<SettingsWrapper> configChangeParams, EventContext eventContext) { bool oldScriptAnalysisEnabled = this.currentSettings.ScriptAnalysis.Enable.HasValue; this.currentSettings.Update( configChangeParams.Settings.Powershell); if (oldScriptAnalysisEnabled != this.currentSettings.ScriptAnalysis.Enable) { // If the user just turned off script analysis, 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); } } } }
protected async Task HandleDidChangeConfigurationNotification( DidChangeConfigurationParams <LanguageServerSettingsWrapper> configChangeParams, EventContext eventContext) { bool oldLoadProfiles = this.currentSettings.EnableProfileLoading; bool oldScriptAnalysisEnabled = this.currentSettings.ScriptAnalysis.Enable.HasValue; string oldScriptAnalysisSettingsPath = this.currentSettings.ScriptAnalysis.SettingsPath; this.currentSettings.Update( configChangeParams.Settings.Powershell, this.editorSession.Workspace.WorkspacePath); if (!this.profilesLoaded && this.currentSettings.EnableProfileLoading && oldLoadProfiles != this.currentSettings.EnableProfileLoading) { await this.editorSession.PowerShellContext.LoadHostProfiles(); this.profilesLoaded = true; } // If there is a new settings file path, restart the analyzer with the new settigs. bool settingsPathChanged = false; string newSettingsPath = this.currentSettings.ScriptAnalysis.SettingsPath; if (!string.Equals(oldScriptAnalysisSettingsPath, newSettingsPath, StringComparison.OrdinalIgnoreCase)) { this.editorSession.RestartAnalysisService(newSettingsPath); settingsPathChanged = true; } // If script analysis settings have changed we need to clear & possibly update the current diagnostic records. if ((oldScriptAnalysisEnabled != this.currentSettings.ScriptAnalysis.Enable) || settingsPathChanged) { // 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 || settingsPathChanged) { ScriptFileMarker[] emptyAnalysisDiagnostics = new ScriptFileMarker[0]; foreach (var scriptFile in editorSession.Workspace.GetOpenedFiles()) { await PublishScriptDiagnostics( scriptFile, emptyAnalysisDiagnostics, eventContext); } } // If script analysis is enabled and the settings file changed get new diagnostic records. if (this.currentSettings.ScriptAnalysis.Enable.Value && settingsPathChanged) { await this.RunScriptDiagnostics( this.editorSession.Workspace.GetOpenedFiles(), this.editorSession, eventContext); } } }