public void UpdateErrors(ITextSnapshot currentSnapshot, LintingErrorsSnapshot lintingErrors) { var oldLintingErrors = _snapshot; _snapshot = lintingErrors; // Raise a single tags changed event over the span that could have been affected by the change in the errors. var start = int.MaxValue; var end = int.MinValue; if (oldLintingErrors?.Errors.Count > 0) { start = oldLintingErrors.Errors[0].Span.Start.TranslateTo(currentSnapshot, PointTrackingMode.Negative); end = oldLintingErrors.Errors[oldLintingErrors.Errors.Count - 1].Span.End.TranslateTo(currentSnapshot, PointTrackingMode.Positive); } if (lintingErrors.Count > 0) { start = Math.Min(start, lintingErrors.Errors[0].Span.Start.Position); end = Math.Max(end, lintingErrors.Errors[lintingErrors.Errors.Count - 1].Span.End.Position); } if (start < end) { TagsChanged?.Invoke(this, new SnapshotSpanEventArgs(new SnapshotSpan(currentSnapshot, Span.FromBounds(start, end)))); } }
public LintTagger(LintChecker lintChecker) { _lintChecker = lintChecker; _snapshot = lintChecker.LastErrorsSnapshot; lintChecker.AddTagger(this); }
private void UpdateLintingErrors(LintingErrorsSnapshot lintSnapshot) { // Tell our factory to snap to a new snapshot. this.Factory.UpdateErrors(lintSnapshot); // Tell the provider to mark all the sinks dirty (so, as a side-effect, they will start an update pass that will get the new snapshot // from the factory). _provider.NotifyAllSinks(); foreach (var tagger in _activeTaggers) { tagger.UpdateErrors(_currentSnapshot, lintSnapshot); } this.LastErrorsSnapshot = lintSnapshot; Updated?.Invoke(this, EventArgs.Empty); }
private void OnBufferChange(object sender, TextContentChangedEventArgs e) { _currentSnapshot = e.After; // Translate all of the old dirty spans to the new snapshot. NormalizedSnapshotSpanCollection newDirtySpans = _dirtySpans.CloneAndTrackTo(e.After, SpanTrackingMode.EdgeInclusive); // Dirty all the spans that changed. foreach (var change in e.Changes) { newDirtySpans = NormalizedSnapshotSpanCollection.Union(newDirtySpans, new NormalizedSnapshotSpanCollection(e.After, change.NewSpan)); } // Translate all the linting errors to the new snapshot (and remove anything that is a dirty region since we will need to check that again). var oldErrors = this.Factory.CurrentSnapshot; var newErrors = new LintingErrorsSnapshot(oldErrors.Document, oldErrors.VersionNumber + 1); // Copy all of the old errors to the new errors unless the error was affected by the text change foreach (var error in oldErrors.Errors) { Debug.Assert(error.NextIndex == -1); var newError = LintError.CloneAndTranslateTo(error, e.After); if (newError != null) { Debug.Assert(newError.Span.Length == error.Span.Length); error.NextIndex = newErrors.Errors.Count; newErrors.Errors.Add(newError); } } this.UpdateLintingErrors(newErrors); _dirtySpans = newDirtySpans; // Start processing the dirty spans (which no-ops if we're already doing it). if (_dirtySpans.Count != 0) { this.RunLinter(); } }
public async Task DoUpdateAsync() { if (IsDisposed) { return; } var buffer = _currentSnapshot; var path = _document.FilePath; // replace with user token var token = _cts.Token; var instance = await FsLintVsPackage.Instance.WithCancellation(token); // this acts as a throttle await Task.Delay(200, token); if (Project == null) { await instance.JoinableTaskFactory.SwitchToMainThreadAsync(); var project = instance.Dte.Solution.FindProjectItem(path)?.ContainingProject; if (project == null) { return; } if (instance.SolutionService.GetProjectOfUniqueName(project.UniqueName, out var vsHierarchy) != VSConstants.S_OK) { return; } if (instance.SolutionService.GetGuidOfProject(vsHierarchy, out var guid) != VSConstants.S_OK) { return; } Project = new LintProjectInfo(project.Name, guid, vsHierarchy); } await Task.Yield(); var connectionString = SqlAnalyzer.tryFindConnectionString(path); if (string.IsNullOrWhiteSpace(connectionString)) { return; } var loadedSchema = SqlAnalysis.databaseSchema(connectionString); if (loadedSchema.IsError) { return; } var source = _currentSnapshot.GetText(); var sourceText = SourceText.ofString(source); var getProjectOptions = _provider.CheckerInstance.GetProjectOptionsFromScript( filename: path, sourceText: sourceText, assumeDotNetFramework: false, useSdkRefs: true, useFsiAuxLib: true, previewEnabled: true, otherFlags: new string[] { "--targetprofile:netstandard" }, loadedTimeStamp: FSharpOption <DateTime> .None, extraProjectInfo: FSharpOption <object> .None, optionsStamp: FSharpOption <long> .None, userOpName: FSharpOption <string> .None ); var(options, errors) = await FSharpAsync.StartAsTask(getProjectOptions, null, token); if (errors.Any()) { return; } var performParseAndCheck = _provider.CheckerInstance.ParseAndCheckFileInProject( filename: path, fileversion: 1, sourceText: sourceText, options: options, textSnapshotInfo: FSharpOption <object> .None, userOpName: FSharpOption <string> .None ); var(parseResults, checkAnswer) = await FSharpAsync.StartAsTask(performParseAndCheck, null, token); if (parseResults.ParseHadErrors || checkAnswer.IsAborted) { return; } var checkResults = SqlAnalyzer.checkAnswerResult(checkAnswer).Value; var context = new SqlAnalyzerContext( fileName: path, content: source.Split('\n'), parseTree: parseResults.ParseTree.Value, symbols: SqlAnalyzer.getSymbols(checkResults) ); var databaseSchema = loadedSchema.ResultValue; var errorMessages = from operation in SyntacticAnalysis.findSqlOperations(context) from analysisOutput in SqlAnalysis.analyzeOperation(operation, connectionString, databaseSchema) select analysisOutput; var oldLintingErrors = this.Factory.CurrentSnapshot; var newLintErrors = new LintingErrorsSnapshot(_document, oldLintingErrors.VersionNumber + 1); foreach (var error in errorMessages) { var span = RangeToSpan(error.Range, buffer); newLintErrors.Errors.Add(new LintError(span, error, Project)); } await instance.JoinableTaskFactory.SwitchToMainThreadAsync(); if (token.IsCancellationRequested) { return; } UpdateLintingErrors(newLintErrors); }
public void UpdateErrors(LintingErrorsSnapshot lintingErrors) { this.CurrentSnapshot.NextSnapshot = lintingErrors; this.CurrentSnapshot = lintingErrors; }
public LintTableSnapshotFactory(LintingErrorsSnapshot lintErrors) { this.CurrentSnapshot = lintErrors; }
public async Task DoUpdateAsync() { if (IsDisposed) { return; } var buffer = _currentSnapshot; var path = _document.FilePath; // replace with user token var token = _cts.Token; var instance = await FsLintVsPackage.Instance.WithCancellation(token); // this acts as a throttle await Task.Delay(200, token); if (Project == null) { await instance.JoinableTaskFactory.SwitchToMainThreadAsync(); var project = instance.Dte.Solution.FindProjectItem(path)?.ContainingProject; if (project == null) { return; } if (instance.SolutionService.GetProjectOfUniqueName(project.UniqueName, out var vsHierarchy) != VSConstants.S_OK) { return; } if (instance.SolutionService.GetGuidOfProject(vsHierarchy, out var guid) != VSConstants.S_OK) { return; } Project = new LintProjectInfo(project.Name, guid, vsHierarchy); } await Task.Yield(); var connectionString = SqlAnalyzer.tryFindConnectionString(path); if (string.IsNullOrWhiteSpace(connectionString)) { return; } var source = _currentSnapshot.GetText(); var sourceText = SourceText.ofString(source); var getProjectOptions = _provider.CheckerInstance.GetProjectOptionsFromScript( filename: path, source: sourceText, assumeDotNetFramework: false, useSdkRefs: true, useFsiAuxLib: true, previewEnabled: true, otherFlags: new string[] { "--targetprofile:netstandard" }, loadedTimeStamp: FSharpOption <DateTime> .None, extraProjectInfo: FSharpOption <object> .None, optionsStamp: FSharpOption <long> .None, userOpName: FSharpOption <string> .None, sdkDirOverride: FSharpOption <string> .None ); var(options, errors) = await FSharpAsync.StartAsTask(getProjectOptions, null, token); if (errors.Any()) { return; } var performParseAndCheck = _provider.CheckerInstance.ParseAndCheckFileInProject( filename: path, fileVersion: 1, sourceText: sourceText, options: options, userOpName: FSharpOption <string> .None ); var(parseResults, checkAnswer) = await FSharpAsync.StartAsTask(performParseAndCheck, null, token); if (parseResults.ParseHadErrors || checkAnswer.IsAborted) { return; } var checkResults = SqlAnalyzer.checkAnswerResult(checkAnswer).Value; var context = new SqlAnalyzerContext( fileName: path, content: source.Split('\n'), parseTree: parseResults.ParseTree.Value, symbols: SqlAnalyzer.getSymbols(checkResults) ); var operationBlocks = SyntacticAnalysis.findSqlOperations(context); var loadedSchema = SqlAnalysis.databaseSchema(connectionString); var errorMessages = new List <Message>(); if (loadedSchema.IsError) { foreach (var operation in operationBlocks) { var containsSkipAnalysis = operation.blocks.Any(block => block.IsSkipAnalysis); foreach (var block in operation.blocks) { var blockRange = block.Range(); if ((block.IsQuery || block.IsTransaction) && OptionModule.IsSome(blockRange) && !containsSkipAnalysis) { var internalError = (loadedSchema.ErrorValue ?? "").Replace("3D000:", "").Replace("28P01:", ""); var fullError = $"Error occured while trying to connect to the database using the configured connection string in NPGSQL_FSHARP in order to perform static analysis:{internalError}"; var errorMessage = new Message( type: "Error", message: fullError, code: "SQL101", severity: Severity.Warning, range: blockRange.Value, fixes: Microsoft.FSharp.Collections.FSharpList <Fix> .Empty ); errorMessages.Add(errorMessage); } } } } else { var databaseSchema = loadedSchema.ResultValue; foreach (var operation in operationBlocks) { foreach (var analysisOutput in SqlAnalysis.analyzeOperation(operation, connectionString, databaseSchema)) { errorMessages.Add(analysisOutput); } } } var oldLintingErrors = this.Factory.CurrentSnapshot; var newLintErrors = new LintingErrorsSnapshot(_document, oldLintingErrors.VersionNumber + 1); foreach (var error in errorMessages) { var span = RangeToSpan(error.Range, buffer); newLintErrors.Errors.Add(new LintError(span, error, Project)); } await instance.JoinableTaskFactory.SwitchToMainThreadAsync(); if (token.IsCancellationRequested) { return; } UpdateLintingErrors(newLintErrors); }