public ClassifierHelper(string code, PythonLanguageVersion version) { _view = new PythonEditor("", version); var providers = _view.VS.ComponentModel.GetExtensions <IClassifierProvider>().ToArray(); _provider1 = providers.OfType <PythonClassifierProvider>().Single(); _provider2 = providers.OfType <PythonAnalysisClassifierProvider>().Single(); _classificationsReady1 = new ManualResetEventSlim(); _classificationsReady2 = new ManualResetEventSlim(); AstClassifier.ClassificationChanged += (s, e) => _classificationsReady1.SetIfNotDisposed(); var startVersion = _view.CurrentSnapshot.Version; AnalysisClassifier.ClassificationChanged += (s, e) => { try { var bi = PythonTextBufferInfo.TryGetForBuffer(_view.View.TextView.TextBuffer); if (bi?.LastAnalysisReceivedVersion == null) { return; } // make sure we have classifications from the version we analyzed after // setting the text below. if (bi.LastAnalysisReceivedVersion.VersionNumber > startVersion.VersionNumber) { _classificationsReady2.SetIfNotDisposed(); } } catch (Exception ex) { _excInfo = ExceptionDispatchInfo.Capture(ex); } }; _view.Text = code; }
private static void ValidateBufferContents(IEnumerable <ITextSnapshot> snapshots, AP.FileUpdateResponse response) { #if DEBUG if (response.newCode == null) { return; } foreach (var snapshot in snapshots) { var bi = PythonTextBufferInfo.TryGetForBuffer(snapshot.TextBuffer); if (bi == null) { continue; } string newCode; if (!response.newCode.TryGetValue(bi.AnalysisBufferId, out newCode)) { continue; } if (newCode.TrimEnd() != snapshot.GetText().TrimEnd()) { Console.Error.WriteLine($"New Code: [{newCode}]"); Console.Error.WriteLine($"Snapshot: [{snapshot.GetText()}]"); Debug.Fail("Buffer content mismatch"); } } #endif }
async Task IPythonTextBufferInfoEventSink.PythonTextBufferEventAsync(PythonTextBufferInfo sender, PythonTextBufferInfoEventArgs e) { if (e.Event == PythonTextBufferInfoEvents.NewAnalysis) { await OnNewAnalysis(sender, e.AnalysisEntry); } }
private void AssertLines(PythonTextBufferInfo buffer, params int[] lengths) { AssertLines( buffer.LocationTracker.GetLineLocations(buffer.Buffer.CurrentSnapshot.Version.VersionNumber), lengths ); }
public void BufferSync_Issue3570() { // https://github.com/Microsoft/PTVS/issues/3570 var buffer = new MockTextBuffer("line"); var bi = PythonTextBufferInfo.ForBuffer(null, buffer); bi.AddSentSnapshot(buffer.CurrentSnapshot); Assert.AreEqual(new SourceLocation(1, 5), bi.LocationTracker.GetSourceLocation(4, 0)); using (var e = buffer.CreateEdit()) { e.Insert(e.Snapshot.Length, "\r\n"); e.Apply(); } using (var e = buffer.CreateEdit()) { e.Insert(e.Snapshot.Length, " c"); e.Apply(); } using (var e = buffer.CreateEdit()) { e.Insert(e.Snapshot.Length, "o"); e.Apply(); } var updates = BufferParser.GetUpdatesForSnapshot(bi, buffer.CurrentSnapshot).ToArray(); var changeInfo = string.Join(", ", updates .Select(u => string.Join(", ", u.changes.Select(c => $"({c.startLine},{c.startColumn},'{c.newText}')"))) .Select(u => $"[{u}]")); Assert.AreEqual("[(1,5,'\r\n')], [(2,1,' c')], [(2,6,'o')]", changeInfo); }
private static void ValidateBufferContents(IEnumerable <ITextSnapshot> snapshots, AP.FileUpdateResponse response) { #if DEBUG if (response.newCode == null) { return; } foreach (var snapshot in snapshots) { var bi = PythonTextBufferInfo.TryGetForBuffer(snapshot.TextBuffer); if (bi == null) { continue; } string newCode; if (!response.newCode.TryGetValue(bi.AnalysisBufferId, out newCode)) { continue; } Debug.Assert(newCode.TrimEnd() == snapshot.GetText().TrimEnd(), "Buffer content mismatch"); } #endif }
internal PythonTextBufferInfo GetBufferInfo() { var bi = PythonTextBufferInfo.TryGetForBuffer(TextBuffer); Debug.Assert(bi != null, "Getting completions from uninitialized buffer " + TextBuffer.ToString()); return(bi); }
async Task IPythonTextBufferInfoEventSink.PythonTextBufferEventAsync(PythonTextBufferInfo sender, PythonTextBufferInfoEventArgs e) { if (_triggerEvents.Contains(e.Event)) { await OnNewAnalysis(sender, e.AnalysisEntry); } }
/// <summary> /// Wired to parser event for when the parser has completed parsing a new tree and we need /// to update the navigation bar with the new data. /// </summary> async Task IPythonTextBufferInfoEventSink.PythonTextBufferEventAsync(PythonTextBufferInfo sender, PythonTextBufferInfoEventArgs e) { if (e.Event == PythonTextBufferInfoEvents.NewParseTree) { var dropDownBar = _dropDownBar; if (dropDownBar == null) { return; } var navigations = await _uiThread.InvokeTask(() => e.AnalysisEntry.Analyzer.GetNavigationsAsync(_textView)); lock (_navigationsLock) { _navigations = navigations; for (int i = 0; i < _curSelection.Length; i++) { _curSelection[i] = -1; } } Action callback = () => CaretPositionChanged( this, new CaretPositionChangedEventArgs( _textView, _textView.Caret.Position, _textView.Caret.Position ) ); try { await _dispatcher.BeginInvoke(callback, DispatcherPriority.Background); } catch (TaskCanceledException) { } } }
internal int RemoveBuffer(ITextBuffer subjectBuffer) { int result; var bi = PythonTextBufferInfo.TryGetForBuffer(subjectBuffer); lock (this) { if (bi != null) { var existing = _buffers.FirstOrDefault(b => b.Buffer == bi); if (existing != null && existing.Release()) { _buffers = _buffers.Where(b => b != existing).ToArray(); bi.RemoveSink(this); VsProjectAnalyzer.DisconnectErrorList(bi); _bufferIdMapping.Remove(bi.AnalysisBufferId); bi.SetAnalysisBufferId(-1); bi.Buffer.Properties.RemoveProperty(typeof(PythonTextBufferInfo)); } } result = _buffers.Length; } return(result); }
internal PythonAnalysisClassifier(PythonAnalysisClassifierProvider provider, PythonTextBufferInfo buffer) { _provider = provider; _buffer = buffer; _buffer.OnNewAnalysis += OnNewAnalysis; _buffer.OnContentTypeChanged += BufferContentTypeChanged; }
internal static AP.ChangeInfo[] GetChanges(PythonTextBufferInfo buffer, ITextVersion curVersion) { var changes = new List <AP.ChangeInfo>(); if (curVersion.Changes != null) { foreach (var change in curVersion.Changes) { var oldPos = buffer.LocationTracker.GetSourceLocation(change.OldPosition, curVersion.VersionNumber); var oldEnd = buffer.LocationTracker.GetSourceLocation(change.OldEnd, curVersion.VersionNumber); changes.Add(new AP.ChangeInfo { startLine = oldPos.Line, startColumn = oldPos.Column, endLine = oldEnd.Line, endColumn = oldEnd.Column, newText = change.NewText, #if DEBUG _startIndex = change.OldPosition, _endIndex = change.OldEnd #endif }); } } #if DEBUG Debug.WriteLine("Getting changes for version {0}", curVersion.VersionNumber); foreach (var c in changes) { Debug.WriteLine($" - ({c.startLine}, {c.startColumn})-({c.endLine}, {c.endColumn}): \"{c.newText}\""); } #endif return(changes.ToArray()); }
public void BasicProjectTest() { var sln = Generator.Project( "HelloWorld", ProjectGenerator.Compile("server", "") ).Generate(); using (var vs = sln.ToMockVs()) { Assert.IsNotNull(vs.WaitForItem("HelloWorld", "Python Environments")); Assert.IsNotNull(vs.WaitForItem("HelloWorld", "References")); Assert.IsNotNull(vs.WaitForItem("HelloWorld", "Search Paths")); Assert.IsNotNull(vs.WaitForItem("HelloWorld", "server.py")); var view = vs.OpenItem("HelloWorld", "server.py"); var bi = PythonTextBufferInfo.TryGetForBuffer(view.TextView.TextBuffer); for (int retries = 20; retries > 0 && bi.AnalysisEntry == null; --retries) { Thread.Sleep(500); } view.Invoke(() => view.Type("import")); view.Invoke(() => view.Type(" ")); using (var sh = view.WaitForSession <ICompletionSession>()) { AssertUtil.Contains(sh.Session.Completions(), "sys"); } } }
private Task OnTextContentChangedAsync(PythonTextBufferInfo sender, TextContentChangedEventArgs e) { if (e == null) { Debug.Fail("Invalid type passed to event"); } var snapshot = e.After; if (!snapshot.IsReplBufferWithCommand()) { _tokenCache.EnsureCapacity(snapshot.LineCount); var tokenizer = GetTokenizer(snapshot); foreach (var change in e.Changes) { if (change.LineCountDelta > 0) { _tokenCache.InsertLines(snapshot.GetLineNumberFromPosition(change.NewEnd) + 1 - change.LineCountDelta, change.LineCountDelta); } else if (change.LineCountDelta < 0) { _tokenCache.DeleteLines(snapshot.GetLineNumberFromPosition(change.NewEnd) + 1, -change.LineCountDelta); } ApplyChange(tokenizer, snapshot, change.NewSpan); } } return(Task.CompletedTask); }
private IEnumerable <CompletionResult> GetAvailableCompletions(PythonTextBufferInfo bufferInfo, SnapshotPoint point) { var analysis = bufferInfo.AnalysisEntry; if (analysis == null) { return(Enumerable.Empty <CompletionResult>()); } var analyzer = analysis.Analyzer; lock (analyzer) { var location = VsProjectAnalyzer.TranslateIndex( point.Position, point.Snapshot, analysis ); var parameters = Enumerable.Empty <CompletionResult>(); var sigs = analyzer.WaitForRequest(analyzer.GetSignaturesAsync(analysis, View, _snapshot, Span), "GetCompletions.GetSignatures"); if (sigs != null && sigs.Signatures.Any()) { parameters = sigs.Signatures .SelectMany(s => s.Parameters) .Select(p => p.Name) .Distinct() .Select(n => new CompletionResult(n + "=", PythonMemberType.NamedArgument)); } return(analyzer.WaitForRequest(analyzer.GetAllAvailableMembersAsync(analysis, location, _options.MemberOptions), "GetCompletions.GetAllAvailableMembers") .MaybeEnumerate() .Union(parameters, CompletionComparer.MemberEquality)); } }
private static bool IsValidBraceCompletionContext(PythonTextBufferInfo buffer, SnapshotPoint openingPoint) { if (buffer == null) { return(false); } Debug.Assert(openingPoint.Position >= 0, "SnapshotPoint.Position should always be zero or positive."); if (openingPoint.Position < 0) { return(false); } // If we have a token here that is in any of these categories, we do // not want to complete. var category = buffer.GetTokenAtPoint(openingPoint)?.Category ?? TokenCategory.None; return(!( category == TokenCategory.Comment || category == TokenCategory.LineComment || category == TokenCategory.DocComment || category == TokenCategory.StringLiteral || category == TokenCategory.IncompleteMultiLineStringLiteral )); }
public OutliningTagger(PythonEditorServices services, PythonTextBufferInfo buffer) { _services = services; _buffer = buffer; _buffer.OnNewParseTree += OnNewParseTree; Enabled = _services.Python?.AdvancedOptions.EnterOutliningModeOnOpen ?? true; }
internal int Unregister(IVsDropdownBarManager manager) { _textView.Caret.PositionChanged -= CaretPositionChanged; // A buffer may have multiple DropDownBarClients, given one may open multiple CodeWindows // over a single buffer using Window/New Window List <DropDownBarClient> clients; if (_textView.Properties.TryGetProperty(typeof(DropDownBarClient), out clients)) { clients.Remove(this); if (clients.Count == 0) { _textView.Properties.RemoveProperty(typeof(DropDownBarClient)); } } foreach (var tb in PythonTextBufferInfo.GetAllFromView(_textView)) { tb.RemoveSink(this); } #if DEBUG IVsDropdownBar existing; IVsDropdownBarClient existingClient; if (ErrorHandler.Succeeded(manager.GetDropdownBar(out existing)) && ErrorHandler.Succeeded(existing.GetClient(out existingClient))) { Debug.Assert(existingClient == this, "Unregistering the wrong dropdown client"); } #endif return(manager.RemoveDropdownBar()); }
internal AnalysisEntry GetAnalysisEntry() { var bi = PythonTextBufferInfo.TryGetForBuffer(TextBuffer); Debug.Assert(bi != null, "Getting completions from uninitialized buffer " + TextBuffer.ToString()); Debug.Assert(bi?.AnalysisEntry != null, "Failed to get project entry for buffer " + TextBuffer.ToString()); return(bi?.AnalysisEntry); }
Task IPythonTextBufferInfoEventSink.PythonTextBufferEventAsync(PythonTextBufferInfo sender, PythonTextBufferInfoEventArgs e) { if (e.Event == PythonTextBufferInfoEvents.NewAnalysis) { return(OnNewAnalysisAsync(sender, e.AnalysisEntry)); } return(Task.CompletedTask); }
Task IPythonTextBufferInfoEventSink.PythonTextBufferEventAsync(PythonTextBufferInfo sender, PythonTextBufferInfoEventArgs e) { if (e.Event == PythonTextBufferInfoEvents.NewAnalysis) { SuggestedActionsChanged?.Invoke(this, EventArgs.Empty); } return(Task.CompletedTask); }
/// <summary> /// Wired to parser event for when the parser has completed parsing a new tree and we need /// to update the navigation bar with the new data. /// </summary> async Task IPythonTextBufferInfoEventSink.PythonTextBufferEventAsync(PythonTextBufferInfo sender, PythonTextBufferInfoEventArgs e) { if (e.Event == PythonTextBufferInfoEvents.NewParseTree) { AnalysisEntry analysisEntry = e.AnalysisEntry; await RefreshNavigationsFromAnalysisEntry(analysisEntry); } }
public void AddBuffer(PythonTextBufferInfo buffer) { buffer.OnNewAnalysis += OnNewAnalysis; if (buffer.AnalysisEntry?.IsAnalyzed == true) { OnNewAnalysis(buffer, EventArgs.Empty); } }
async Task IPythonTextBufferInfoEventSink.PythonTextBufferEventAsync(PythonTextBufferInfo sender, PythonTextBufferInfoEventArgs e) { if (e.Event == PythonTextBufferInfoEvents.NewParseTree) { // TODO: Reconsider whether we process asynchronously and then marshal // at the end. await _services.Site.GetUIThread().InvokeTask(() => UpdateTagsAsync(sender, e.AnalysisEntry)); } }
internal bool GetPrecedingExpression(out string parentExpression, out SnapshotSpan expressionExtent) { parentExpression = string.Empty; expressionExtent = default(SnapshotSpan); var bi = PythonTextBufferInfo.TryGetForBuffer(_snapshot.TextBuffer); if (bi == null) { return(false); } var span = Span.GetSpan(_snapshot); var expr = bi.GetExpressionAtPoint(span, GetExpressionOptions.EvaluateMembers); if (expr != null) { parentExpression = expr.Value.GetText() ?? ""; expressionExtent = new SnapshotSpan(expr.Value.Start, span.End); return(true); } expr = bi.GetExpressionAtPoint(span, GetExpressionOptions.Rename); if (expr != null) { expressionExtent = expr.Value; return(true); } var tok = bi.GetTokenAtPoint(span.End); if (tok == null) { expressionExtent = span; return(true); } switch (tok.Value.Category) { case TokenCategory.Delimiter: case TokenCategory.Grouping: case TokenCategory.Operator: case TokenCategory.WhiteSpace: // Expect top-level completions after these expressionExtent = span; return(true); case TokenCategory.BuiltinIdentifier: case TokenCategory.Identifier: case TokenCategory.Keyword: // Expect filtered top-level completions here // (but the return value is no different) expressionExtent = span; return(true); } return(false); }
Task IPythonTextBufferInfoEventSink.PythonTextBufferEventAsync(PythonTextBufferInfo sender, PythonTextBufferInfoEventArgs e) { switch (e.Event) { case PythonTextBufferInfoEvents.TextContentChangedLowPriority: lock (this) { // only immediately re-parse on line changes after we've seen a text change. var ne = (e as PythonTextBufferInfoNestedEventArgs)?.NestedEventArgs as TextContentChangedEventArgs; if (_parsing) { // we are currently parsing, just reque when we complete _requeue = true; _timer.Change(Timeout.Infinite, Timeout.Infinite); } else if (_parseImmediately) { // we are a test buffer, we should requeue immediately Requeue(); } else if (ne == null) { // failed to get correct type for this event Debug.Fail("Failed to get correct event type"); } else if (LineAndTextChanges(ne)) { // user pressed enter, we should requeue immediately Requeue(); } else { // parse if the user doesn't do anything for a while. _textChange = IncludesTextChanges(ne); _timer.Change(ReparseDelay, Timeout.Infinite); } } break; case PythonTextBufferInfoEvents.DocumentEncodingChanged: lock (this) { if (_parsing) { // we are currently parsing, just reque when we complete _requeue = true; _timer.Change(Timeout.Infinite, Timeout.Infinite); } else { Requeue(); } } break; } return(Task.CompletedTask); }
public void AddBuffer(PythonTextBufferInfo buffer) { buffer.AddSink(typeof(T), this); if (buffer.AnalysisEntry?.IsAnalyzed == true) { OnNewAnalysis(buffer, buffer.AnalysisEntry) .HandleAllExceptions(Services.Site, GetType()) .DoNotWait(); } }
public void AddBuffer(PythonTextBufferInfo buffer) { buffer.AddSink(typeof(UnresolvedImportSquiggleProvider), this); if (buffer.AnalysisEntry?.IsAnalyzed == true) { OnNewAnalysis(buffer, buffer.AnalysisEntry) .HandleAllExceptions(_services.Site, GetType()) .DoNotWait(); } }
public static Task <AnalysisEntry> GetAnalysisEntryAsync(this ITextBuffer buffer, PythonEditorServices services = null, CancellationToken cancellationToken = default(CancellationToken)) { var bi = services == null?PythonTextBufferInfo.TryGetForBuffer(buffer) : services.GetBufferInfo(buffer); if (bi != null) { return(bi.GetAnalysisEntryAsync(cancellationToken)); } return(Task.FromResult <AnalysisEntry>(null)); }
private void BufferGraph_GraphBuffersChanged(object sender, VisualStudio.Text.Projection.GraphBuffersChangedEventArgs e) { foreach (var b in e.RemovedBuffers) { PythonTextBufferInfo.TryGetForBuffer(b)?.RemoveSink(typeof(DropDownBarClient)); } foreach (var b in e.AddedBuffers) { _services.GetBufferInfo(b).AddSink(typeof(DropDownBarClient), this); } }