internal static async Task ParseBuffersAsync( PythonEditorServices services, VsProjectAnalyzer analyzer, IEnumerable <ITextSnapshot> snapshots ) { var updates = snapshots .GroupBy(s => PythonTextBufferInfo.TryGetForBuffer(s.TextBuffer)?.AnalysisEntry.FileId ?? -1) .Where(g => g.Key >= 0) .Select(g => Tuple.Create( g.Key, g.Select(s => GetUpdateForSnapshot(services, s)).Where(u => u != null).ToArray() )) .ToList(); if (!updates.Any()) { return; } foreach (var update in updates) { if (update.Item1 < 0) { continue; } analyzer._analysisComplete = false; Interlocked.Increment(ref analyzer._parsePending); var res = await analyzer.SendRequestAsync( new AP.FileUpdateRequest() { fileId = update.Item1, updates = update.Item2 } ); if (res != null) { Debug.Assert(res.failed != true); analyzer.OnAnalysisStarted(); ValidateBufferContents(snapshots, res); } else { Interlocked.Decrement(ref analyzer._parsePending); } } }
internal static async Task ParseBuffersAsync( PythonEditorServices services, VsProjectAnalyzer analyzer, IEnumerable <ITextSnapshot> snapshots ) { var tasks = new List <Tuple <ITextSnapshot[], Task <AP.FileUpdateResponse> > >(); foreach (var snapshotGroup in snapshots.GroupBy(s => PythonTextBufferInfo.TryGetForBuffer(s.TextBuffer))) { var entry = snapshotGroup.Key?.AnalysisEntry; if (entry == null) { continue; } var updates = snapshotGroup.Select(s => GetUpdateForSnapshot(snapshotGroup.Key, s)).Where(u => u != null).ToArray(); if (!updates.Any()) { continue; } analyzer._analysisComplete = false; Interlocked.Increment(ref analyzer._parsePending); tasks.Add(Tuple.Create(snapshotGroup.ToArray(), analyzer.SendRequestAsync( new AP.FileUpdateRequest { fileId = entry.FileId, updates = updates } ))); } foreach (var task in tasks) { var res = await task.Item2; if (res != null) { Debug.Assert(res.failed != true); analyzer.OnAnalysisStarted(); ValidateBufferContents(task.Item1, res); } else { Interlocked.Decrement(ref analyzer._parsePending); } } }
private async Task ParseBuffers(ITextSnapshot[] snapshots, BufferInfo[] bufferInfos) { var indentationSeverity = _parser.PyService.GeneralOptions.IndentationInconsistencySeverity; AnalysisEntry entry = AnalysisEntry; List <AP.FileUpdate> updates = new List <AP.FileUpdate>(); lock (this) { for (int i = 0; i < snapshots.Length; i++) { var snapshot = snapshots[i]; var bufferInfo = bufferInfos[i]; if (snapshot.TextBuffer.Properties.ContainsProperty(DoNotParse) || snapshot.IsReplBufferWithCommand()) { continue; } var lastSent = GetLastSentSnapshot(bufferInfo.Buffer); if (lastSent == null || lastSent.TextBuffer != snapshot.TextBuffer) { // First time parsing from a live buffer, send the entire // file and set our initial snapshot. We'll roll forward // to new snapshots when we receive the errors event. This // just makes sure that the content is in sync. updates.Add( new AP.FileUpdate() { content = snapshot.GetText(), version = snapshot.Version.VersionNumber, bufferId = bufferInfo.Id, kind = AP.FileUpdateKind.reset } ); } else { if (lastSent.Version == snapshot.Version) { // this snapshot is up to date... continue; } List <AP.VersionChanges> versions = new List <AnalysisProtocol.VersionChanges>(); for (var curVersion = lastSent.Version; curVersion != snapshot.Version; curVersion = curVersion.Next) { versions.Add( new AP.VersionChanges() { changes = GetChanges(curVersion) } ); } updates.Add( new AP.FileUpdate() { versions = versions.ToArray(), version = snapshot.Version.VersionNumber, bufferId = bufferInfo.Id, kind = AP.FileUpdateKind.changes } ); } Debug.WriteLine("Added parse request {0}", snapshot.Version.VersionNumber); entry.AnalysisCookie = new SnapshotCookie(snapshot); // TODO: What about multiple snapshots? SetLastSentSnapshot(snapshot); } } if (updates.Count != 0) { _parser._analysisComplete = false; Interlocked.Increment(ref _parser._parsePending); var res = await _parser.SendRequestAsync( new AP.FileUpdateRequest() { fileId = entry.FileId, updates = updates.ToArray() } ); if (res != null) { Debug.Assert(res.failed != true); _parser.OnAnalysisStarted(); #if DEBUG for (int i = 0; i < bufferInfos.Length; i++) { var snapshot = snapshots[i]; var buffer = bufferInfos[i]; string newCode; if (res.newCode.TryGetValue(buffer.Id, out newCode)) { Debug.Assert(newCode == snapshot.GetText(), "Buffer content mismatch - safe to ignore"); } } #endif } else { Interlocked.Decrement(ref _parser._parsePending); } } }
internal static async Task ParseBuffersAsync( PythonEditorServices services, VsProjectAnalyzer analyzer, IEnumerable <ITextSnapshot> snapshots, bool retryOnFailure ) { var tasks = new List <Tuple <ITextSnapshot[], Task <AP.FileUpdateResponse> > >(); foreach (var snapshotGroup in snapshots.GroupBy(s => PythonTextBufferInfo.TryGetForBuffer(s.TextBuffer))) { var entry = snapshotGroup.Key?.AnalysisEntry; if (entry == null) { continue; } var updates = snapshotGroup.SelectMany(s => GetUpdatesForSnapshot(snapshotGroup.Key, s)).Where(u => u != null).ToArray(); if (!updates.Any()) { continue; } analyzer._analysisComplete = false; Interlocked.Increment(ref analyzer._parsePending); tasks.Add(Tuple.Create(snapshotGroup.ToArray(), analyzer.SendRequestAsync( new AP.FileUpdateRequest { documentUri = entry.DocumentUri, updates = updates } ))); } var needRetry = new List <ITextSnapshot>(); foreach (var task in tasks) { var res = await task.Item2; if (res?.failed ?? false) { Interlocked.Decrement(ref analyzer._parsePending); if (res != null) { needRetry.AddRange(task.Item1); } } else { analyzer.OnAnalysisStarted(); ValidateBufferContents(task.Item1, res); } } if (retryOnFailure && needRetry.Any()) { foreach (var bi in needRetry.Select(s => PythonTextBufferInfo.TryGetForBuffer(s.TextBuffer))) { bi.ClearSentSnapshot(); } await ParseBuffersAsync(services, analyzer, needRetry, false); } }