public LintTagger(LintChecker lintChecker) { _lintChecker = lintChecker; _snapshot = lintChecker.LastErrorsSnapshot; lintChecker.AddTagger(this); }
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)))); } }
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 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); if (token.IsCancellationRequested) { return; } // this acts as a throttle await Task.Delay(instance.Options.Throttle, token).ConfigureAwait(false); if (token.IsCancellationRequested) { return; } if (ProjectInfo == null) { await instance.JoinableTaskFactory.SwitchToMainThreadAsync(); var solution = instance.Dte.Solution; var project = 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; } ProjectInfo = new LintProjectInfo(project, solution, guid, vsHierarchy); } if (Configuration == null) { this.Configuration = new[] { Document.FilePath, ProjectInfo.Project.FileName, ProjectInfo.Solution.FileName, Directory.GetParent(ProjectInfo.Solution.FileName).FullName } .Select(Path.GetDirectoryName) .Where(dir => !string.IsNullOrEmpty(dir)) .Select(dir => Path.Combine(dir, "fsharplint.json")) .Where(File.Exists) .Select(Lint.ConfigurationParam.NewFromFile) .FirstOrDefault() ?? Lint.ConfigurationParam.Default; } await Task.Yield(); var lintOpts = new Lint.OptionalLintParameters( cancellationToken: token, configuration: this.Configuration, receivedWarning: null, reportLinterProgress: null); var source = _currentSnapshot.GetText(); var sourceText = SourceText.ofString(source); var parse = instance.Options.TypeCheck ? TryParseAndCheckAsync(path, sourceText, token) : TryParseAsync(path, sourceText, token); var(parseResultsOpt, checkResults) = await parse.ConfigureAwait(false); if (parseResultsOpt == null || parseResultsOpt.Value.ParseHadErrors || token.IsCancellationRequested) { return; } var parseResults = parseResultsOpt.Value; var input = new Lint.ParsedFileInformation(ast: parseResults.ParseTree.Value, source, checkResults); var lintResult = Lint.lintParsedSource(lintOpts, input); if (!lintResult.TryGetSuccess(out var lintWarnings)) { return; } var oldLintingErrors = this.Factory.CurrentSnapshot; var newLintErrors = new LintingErrorsSnapshot(Document, oldLintingErrors.VersionNumber + 1); foreach (var lint in lintWarnings) { var span = RangeToSpan(lint.Details.Range, buffer); newLintErrors.Errors.Add(new LintError(span, lint, ProjectInfo)); } await instance.JoinableTaskFactory.SwitchToMainThreadAsync(); if (token.IsCancellationRequested) { return; } UpdateLintingErrors(newLintErrors); }