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))));
            }
        }
예제 #3
0
        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);
        }
예제 #4
0
        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;
 }
예제 #7
0
        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);
        }