private void SourceBuffersChanged(object sender, ProjectionSourceBuffersChangedEventArgs e) { IProjectionBufferBase projBuffer = (IProjectionBufferBase)sender; FrugalList <ITextBuffer> addedToGraphBuffers = new FrugalList <ITextBuffer>(); FrugalList <ITextBuffer> removedFromGraphBuffers = new FrugalList <ITextBuffer>(); foreach (ITextBuffer addedBuffer in e.AddedBuffers) { AddSourceBuffer(projBuffer, addedBuffer, addedToGraphBuffers); } foreach (ITextBuffer removedBuffer in e.RemovedBuffers) { RemoveSourceBuffer(projBuffer, removedBuffer, removedFromGraphBuffers); } if (addedToGraphBuffers.Count > 0 || removedFromGraphBuffers.Count > 0) { var listeners = GraphBuffersChanged; if (listeners != null) { ((BaseBuffer)projBuffer).group.EnqueueEvents (new GraphEventRaiser(this, new GraphBuffersChangedEventArgs(addedToGraphBuffers, removedFromGraphBuffers)), null); } } }
public ElisionMap EditSpans(ITextSnapshot sourceSnapshot, NormalizedSpanCollection spansToElide, NormalizedSpanCollection spansToExpand, out FrugalList <TextChange> textChanges) { textChanges = new FrugalList <TextChange>(); NormalizedSpanCollection beforeSourceSpans = new NormalizedSnapshotSpanCollection(GetSourceSpans(sourceSnapshot, 0, this.spanCount)); NormalizedSpanCollection afterElisionSourceSpans = NormalizedSpanCollection.Difference(beforeSourceSpans, spansToElide); NormalizedSpanCollection elisionChangeSpans = NormalizedSpanCollection.Difference(beforeSourceSpans, afterElisionSourceSpans); foreach (Span s in elisionChangeSpans) { textChanges.Add(new TextChange(this.root.MapFromSourceSnapshotToNearest(s.Start, 0), new ReferenceChangeString(new SnapshotSpan(sourceSnapshot, s)), ChangeString.EmptyChangeString, sourceSnapshot)); } NormalizedSpanCollection afterExpansionSourceSpans = NormalizedSpanCollection.Union(afterElisionSourceSpans, spansToExpand); NormalizedSpanCollection expansionChangeSpans = NormalizedSpanCollection.Difference(afterExpansionSourceSpans, afterElisionSourceSpans); foreach (Span s in expansionChangeSpans) { textChanges.Add(new TextChange(this.root.MapFromSourceSnapshotToNearest(s.Start, 0), ChangeString.EmptyChangeString, new ReferenceChangeString(new SnapshotSpan(sourceSnapshot, s)), sourceSnapshot)); } return(textChanges.Count > 0 ? new ElisionMap(sourceSnapshot, afterExpansionSourceSpans) : this); }
internal void ComputeSourceEdits(FrugalList <TextChange> changes) { ITextEdit xedit = this.group.GetEdit((BaseBuffer)this.sourceBuffer); foreach (TextChange change in changes) { if (change.OldLength > 0) { IList <SnapshotSpan> sourceDeletionSpans = this.currentElisionSnapshot.MapToSourceSnapshots(new Span(change.OldPosition, change.OldLength)); foreach (SnapshotSpan sourceDeletionSpan in sourceDeletionSpans) { xedit.Delete(sourceDeletionSpan); } } if (change.NewLength > 0) { // change includes an insertion ReadOnlyCollection <SnapshotPoint> sourceInsertionPoints = this.currentElisionSnapshot.MapInsertionPointToSourceSnapshots(change.OldPosition, null); if (sourceInsertionPoints.Count == 1) { // the insertion point is unambiguous xedit.Insert(sourceInsertionPoints[0].Position, change.NewText); } else { // the insertion is at the boundary of source spans int[] insertionSizes = new int[sourceInsertionPoints.Count]; if (this.resolver != null) { this.resolver.FillInInsertionSizes(new SnapshotPoint(this.currentElisionSnapshot, change.OldPosition), sourceInsertionPoints, change.NewText, insertionSizes); } // if resolver was not provided, we just use zeros for the insertion sizes, which will push the entire insertion // into the last slot. int pos = 0; for (int i = 0; i < insertionSizes.Length; ++i) { // contend with any old garbage that the client passed back. int size = (i == insertionSizes.Length - 1) ? change.NewLength - pos : Math.Min(insertionSizes[i], change.NewLength - pos); if (size > 0) { xedit.Insert(sourceInsertionPoints[i].Position, TextChange.ChangeNewSubstring(change, pos, size)); pos += size; if (pos == change.NewLength) { break; // inserted text is used up, whether we've visited all of the insertionSizes or not } } } } } } this.editApplicationInProgress = true; }
public BufferGraph(ITextBuffer topBuffer, GuardedOperations guardedOperations) { if (topBuffer == null) { throw new ArgumentNullException("topBuffer"); } if (guardedOperations == null) { throw new ArgumentNullException("guardedOperations"); } this.topBuffer = topBuffer; this.guardedOperations = guardedOperations; this.importingProjectionBufferMap.Add(topBuffer, null); // The top buffer has no targets, but it is put here so membership in this map can be used uniformly // to determine whether a buffer is in the buffer graph // Subscribe to content type changed events on the toplevel buffer this.eventHooks.Add(new WeakEventHookForBufferGraph(this, topBuffer)); IProjectionBufferBase projectionBufferBase = topBuffer as IProjectionBufferBase; if (projectionBufferBase != null) { IList <ITextBuffer> sourceBuffers = projectionBufferBase.SourceBuffers; FrugalList <ITextBuffer> dontCare = new FrugalList <ITextBuffer>(); foreach (ITextBuffer sourceBuffer in sourceBuffers) { AddSourceBuffer(projectionBufferBase, sourceBuffer, dontCare); } } }
private async Task <(IList <object> items, IList <ITrackingSpan> applicableToSpans)> ComputeContentAsync( IEnumerable <OrderedSource> unorderedSources, IList <Exception> failures, CancellationToken cancellationToken) { // Ensure we're off the UI thread. await TaskScheduler.Default; cancellationToken.ThrowIfCancellationRequested(); var items = new FrugalList <object>(); var applicableToSpans = new FrugalList <ITrackingSpan>(); // Sources from the cache are from the flattened projection buffer graph // so they're initially out of order. We recorded their MEF ordering in // a property though so we can reorder them now. foreach (var source in unorderedSources.OrderBy(source => source.Order)) { // This code is sequential to enable back-compat with the IQuickInfo* APIs, // but when the shims are removed, consider parallelizing as a potential optimization. await this.ComputeSourceContentAsync( source.Source, items, applicableToSpans, failures, cancellationToken).ConfigureAwait(false); } return(items, applicableToSpans); }
public FrugalList <SnapshotPoint> MapInsertionPointToSourceSnapshots(IElisionSnapshot elisionSnapshot, int exposedPosition) { FrugalList <SnapshotPoint> points = new FrugalList <SnapshotPoint>(); this.root.MapInsertionPointToSourceSnapshots(elisionSnapshot, exposedPosition, 0, points); return(points); }
public IEnumerable <TSource> GetSources(IEnumerable <ITextBuffer> buffers) { if (_textView.IsClosed) { Debug.Fail("Intellisense is trying to operate after its view has been closed."); return(Enumerable.Empty <TSource>()); } // For each buffer that should be involved, either return the cached source for that buffer, or create a source and // cache it for later use. IList <TSource> sources = new FrugalList <TSource>(); foreach (var buffer in buffers) { var bufferSources = (IReadOnlyCollection <TSource>)_bufferCache[buffer]; if (bufferSources == null) { bufferSources = _sourceCreator(buffer); _bufferCache.Add(buffer, bufferSources); buffer.ContentTypeChanged += OnContentTypeChanged; } foreach (var source in bufferSources) { sources.Add(source); } } return(sources); }
private async Task <IList <Exception> > ComputeContentAndUpdateAsync(QuickInfoSessionState initialState, bool allowUpdate, CancellationToken cancellationToken) { IntellisenseUtilities.ThrowIfNotOnMainThread(this.JoinableTaskContext); // Alert subscribers on the UI thread. this.TransitionTo(QuickInfoSessionState.Calculating, allowUpdate); cancellationToken.ThrowIfCancellationRequested(); var failures = new FrugalList <Exception>(); // Find and create the sources. Sources cache is smart enough to // invalidate on content-type changed and free on view close. var sources = this.GetOrCreateSources(failures); // Compute quick info items. This method switches off the UI thread. // From here on out we're on an arbitrary thread. (IList <object> items, IList <ITrackingSpan> applicableToSpans)? results = await ComputeContentAsync(sources, failures, cancellationToken).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); // Update our content, or put the empty list if there is none. Volatile.Write( ref this.content, results != null ? ImmutableList.CreateRange(results.Value.items) : ImmutableList <object> .Empty); await StartUIThreadEpilogueAsync(initialState, results?.applicableToSpans, cancellationToken).ConfigureAwait(false); return(failures); }
public ElisionMap EditSpans(ITextSnapshot sourceSnapshot, NormalizedSpanCollection spansToElide, NormalizedSpanCollection spansToExpand, out FrugalList <TextChange> textChanges) { textChanges = new FrugalList <TextChange>(); NormalizedSpanCollection beforeSourceSpans = new NormalizedSnapshotSpanCollection(GetSourceSpans(sourceSnapshot, 0, this.spanCount)); NormalizedSpanCollection afterElisionSourceSpans = NormalizedSpanCollection.Difference(beforeSourceSpans, spansToElide); NormalizedSpanCollection elisionChangeSpans = NormalizedSpanCollection.Difference(beforeSourceSpans, afterElisionSourceSpans); foreach (Span s in elisionChangeSpans) { textChanges.Add(TextChange.Create(this.root.MapFromSourceSnapshotToNearest(s.Start, 0), BufferFactoryService.StringRebuilderFromSnapshotAndSpan(sourceSnapshot, s), StringRebuilder.Empty, sourceSnapshot)); } NormalizedSpanCollection afterExpansionSourceSpans = NormalizedSpanCollection.Union(afterElisionSourceSpans, spansToExpand); NormalizedSpanCollection expansionChangeSpans = NormalizedSpanCollection.Difference(afterExpansionSourceSpans, afterElisionSourceSpans); foreach (Span s in expansionChangeSpans) { textChanges.Add(TextChange.Create(this.root.MapFromSourceSnapshotToNearest(s.Start, 0), StringRebuilder.Empty, BufferFactoryService.StringRebuilderFromSnapshotAndSpan(sourceSnapshot, s), sourceSnapshot)); } return(textChanges.Count > 0 ? new ElisionMap(sourceSnapshot, afterExpansionSourceSpans) : this); }
private SnapshotPoint?MapUpToBufferGuts(SnapshotPoint currentPoint, PositionAffinity affinity, Predicate <ITextSnapshot> match) { if (match(currentPoint.Snapshot)) { return(currentPoint); } FrugalList <IProjectionBufferBase> targetBuffers = this.importingProjectionBufferMap[currentPoint.Snapshot.TextBuffer]; if (targetBuffers != null) // targetBuffers will be null if we fell off the top { foreach (IProjectionBufferBase projBuffer in targetBuffers) { SnapshotPoint?position = projBuffer.CurrentSnapshot.MapFromSourceSnapshot(currentPoint, affinity); if (position.HasValue) { position = MapUpToBufferGuts(position.Value, affinity, match); if (position.HasValue) { return(position); } } } } return(null); }
private IEnumerable <IMappingTagSpan <T> > InternalGetTags(NormalizedSnapshotSpanCollection snapshotSpans, CancellationToken?cancel) { ITextSnapshot targetSnapshot = snapshotSpans[0].Snapshot; bool mapByContentType = (options & TagAggregatorOptions.MapByContentType) != 0; foreach (var bufferAndTaggers in taggers) { if (bufferAndTaggers.Value.Count > 0) { FrugalList <SnapshotSpan> targetSpans = new FrugalList <SnapshotSpan>(); for (int s = 0; s < snapshotSpans.Count; ++s) { MappingHelper.MapDownToBufferNoTrack(snapshotSpans[s], bufferAndTaggers.Key, targetSpans, mapByContentType); } if (targetSpans.Count > 0) { NormalizedSnapshotSpanCollection targetSpanCollection = new NormalizedSnapshotSpanCollection(targetSpans); foreach (var tagSpan in this.GetTagsForBuffer(bufferAndTaggers, targetSpanCollection, targetSnapshot, cancel)) { yield return(tagSpan); } } } } }
private void AddSourceBuffer(IProjectionBufferBase projBuffer, ITextBuffer sourceBuffer, FrugalList <ITextBuffer> addedToGraphBuffers) { bool firstEncounter = false; FrugalList <IProjectionBufferBase> importingProjectionBuffers; if (!this.importingProjectionBufferMap.TryGetValue(sourceBuffer, out importingProjectionBuffers)) { // sourceBuffer is new to this buffer graph addedToGraphBuffers.Add(sourceBuffer); firstEncounter = true; importingProjectionBuffers = new FrugalList <IProjectionBufferBase>(); this.importingProjectionBufferMap.Add(sourceBuffer, importingProjectionBuffers); this.eventHooks.Add(new WeakEventHookForBufferGraph(this, sourceBuffer)); } importingProjectionBuffers.Add(projBuffer); if (firstEncounter) { IProjectionBufferBase addedProjBufferBase = sourceBuffer as IProjectionBufferBase; if (addedProjBufferBase != null) { foreach (ITextBuffer furtherSourceBuffer in addedProjBufferBase.SourceBuffers) { AddSourceBuffer(addedProjBufferBase, furtherSourceBuffer, addedToGraphBuffers); } } } }
public void AddOne() { var list = new FrugalList <int>(); list.Add(42); AssertList(list, 42); }
public void AddTwo() { var list = new FrugalList <int>(); list.Add(1); list.Add(2); AssertList(list, 1, 2); }
internal void AddBaseType(IClassificationType baseType) { if (this.baseTypes == null) { this.baseTypes = new FrugalList <IClassificationType>(); } this.baseTypes.Add(baseType); }
public IList <SnapshotSpan> GetSourceSpans(ITextSnapshot sourceSnapshot, int startSpanIndex, int count) { FrugalList <SnapshotSpan> result = new FrugalList <SnapshotSpan>(); int rank = -1; int sourcePrefixSize = 0; this.root.GetSourceSpans(sourceSnapshot, ref rank, ref sourcePrefixSize, startSpanIndex, startSpanIndex + count, result); return(result); }
public static bool CanMapDownToBuffer(ITextView textView, ITextBuffer textBuffer, ITrackingPoint triggerPoint) { SnapshotPoint triggerSnapshotPoint = triggerPoint.GetPoint(textView.TextSnapshot); var triggerSpan = new SnapshotSpan(triggerSnapshotPoint, 0); var mappedSpans = new FrugalList <SnapshotSpan>(); MappingHelper.MapDownToBufferNoTrack(triggerSpan, textBuffer, mappedSpans); return(mappedSpans.Count > 0); }
public override ReadOnlyCollection <Span> MapFromSourceSnapshot(SnapshotSpan span) { if (span.Snapshot != this.sourceSnapshot) { throw new ArgumentException("The span does not belong to a source snapshot of the projection snapshot"); } FrugalList <Span> result = new FrugalList <Span>(); this.content.MapFromSourceSnapshot(span, result); return(new ReadOnlyCollection <Span>(result)); }
public void MapFromSourceSnapshot(Span span, FrugalList <Span> result) { if (span.Length == 0) { this.root.MapNullSpanFromSourceSnapshot(span, 0, result); } else { this.root.MapFromSourceSnapshot(span, 0, result); } }
protected Edit(BaseBuffer baseBuffer, ITextSnapshot originSnapshot, EditOptions options, int?reiteratedVersionNumber, Object editTag) : base(baseBuffer, originSnapshot, editTag) { this.bufferLength = originSnapshot.Length; this.changes = new FrugalList <TextChange>(); this.options = options; this.reiteratedVersionNumber = reiteratedVersionNumber; this.raisedChangingEventArgs = null; this.cancelAction = null; this.hasFailedChanges = false; }
public void AddMany() { var list = new FrugalList <int>(); var range = Enumerable.Range(0, 5); foreach (var cur in range) { list.Add(cur); } AssertList(list, range.ToArray()); }
private ITextEventRaiser ApplyChangesAndSetSnapshot(FrugalList <TextChange> changes, EditOptions options, int?reiteratedVersionNumber, object editTag) { INormalizedTextChangeCollection normalizedChanges = NormalizedTextChangeCollection.Create(changes, options.ComputeMinimalChange ? (StringDifferenceOptions?)options.DifferenceOptions : null, this.textDifferencingService); ITextSnapshot originSnapshot = base.CurrentSnapshot; base.SetCurrentVersionAndSnapshot(normalizedChanges, reiteratedVersionNumber ?? -1); return(new TextContentChangedEventRaiser(originSnapshot, this.CurrentSnapshot, options, editTag)); }
// Add the range of line numbers on snapshot whose leading whitespace might be affected by a change to span. private static void AddWhitespaceLines(ref FrugalList <Span> whitespaceLines, ITextSnapshot snapshot, Span span) { var startLine = snapshot.GetLineFromPosition(span.Start); var endLine = (span.End < startLine.EndIncludingLineBreak) ? startLine : snapshot.GetLineFromPosition(span.End); // Changes that don't start at the beginning of a line can't affect the starting character of that line. int startLineNumber = (span.Start == startLine.Start) ? startLine.LineNumber : (startLine.LineNumber + 1); int endLineNumber = endLine.LineNumber + 1; AddSpanToLines(ref whitespaceLines, startLineNumber, endLineNumber); }
private static void AddSpanToLines(ref FrugalList <Span> lines, int startLineNumber, int endLineNumber) { if (startLineNumber != endLineNumber) { if (lines == null) { lines = new FrugalList <Span>(); } lines.Add(Span.FromBounds(startLineNumber, endLineNumber)); } }
public void AddExhaustive() { const int count = 20; var list = new FrugalList <int>(); var range = Enumerable.Range(0, count).ToArray(); for (int i = 0; i < range.Length; i++) { list.Add(range[i]); AssertList(list, Enumerable.Range(0, i + 1).ToArray()); } }
// Add the range of line numbers on snapshot whose line endings might be affected by a change to span. private static void AddLineBreakLines(ref FrugalList <Span> lineBreakLines, ITextSnapshot snapshot, Span span) { var startLine = snapshot.GetLineFromPosition(span.Start); var endLine = (span.End < startLine.EndIncludingLineBreak) ? startLine : snapshot.GetLineFromPosition(span.End); // Extend the range if the span starts at the start of a line (since it could affect the line break of the previous line) // or touches the line break at the end of the line). int startLineNumber = ((span.Start == startLine.Start) && (span.Start != 0)) ? (startLine.LineNumber - 1) : startLine.LineNumber; int endLineNumber = (span.End < endLine.End) ? endLine.LineNumber : (endLine.LineNumber + 1); AddSpanToLines(ref lineBreakLines, startLineNumber, endLineNumber); }
public ElisionMap IncorporateChanges(INormalizedTextChangeCollection sourceChanges, FrugalList <TextChange> projectedChanges, ITextSnapshot beforeSourceSnapshot, ITextSnapshot sourceSnapshot, ITextSnapshot beforeElisionSnapshot) { ElisionMapNode newRoot = this.root; int accumulatedProjectedDelta = 0; foreach (ITextChange sourceChange in sourceChanges) { int accumulatedDelete = 0; int incrementalAccumulatedProjectedDelta = 0; ChangeString newText; TextChange concreteSourceChange = sourceChange as TextChange; if (concreteSourceChange != null) { newText = concreteSourceChange._newText; } else { // handle mocks in tests newText = new LiteralChangeString(sourceChange.NewText); } newRoot = newRoot.IncorporateChange(beforeSourceSnapshot: beforeSourceSnapshot, afterSourceSnapshot: sourceSnapshot, beforeElisionSnapshot: beforeElisionSnapshot, sourceInsertionPosition: sourceChange.NewLength > 0 ? sourceChange.NewPosition : (int?)null, newText: newText, sourceDeletionSpan: new Span(sourceChange.NewPosition, sourceChange.OldLength), absoluteSourceOldPosition: sourceChange.OldPosition, absoluteSourceNewPosition: sourceChange.NewPosition, projectedPrefixSize: 0, projectedChanges: projectedChanges, incomingAccumulatedDelta: accumulatedProjectedDelta, outgoingAccumulatedDelta: ref incrementalAccumulatedProjectedDelta, accumulatedDelete: ref accumulatedDelete); accumulatedProjectedDelta += incrementalAccumulatedProjectedDelta; } if (newRoot.TotalSourceSize != sourceSnapshot.Length) { Debug.Fail(String.Format(System.Globalization.CultureInfo.InvariantCulture, "Change incorporation length inconsistency. Elision:{0} Source:{1}", newRoot.TotalSourceSize, sourceSnapshot.Length)); throw new InvalidOperationException(Strings.InvalidLengthCalculation); } if (newRoot.TotalSourceLineBreakCount + 1 != sourceSnapshot.LineCount) { Debug.Fail(String.Format(System.Globalization.CultureInfo.InvariantCulture, "Change incorporation line count inconsistency. Elision:{0} Source:{1}", newRoot.TotalSourceLineBreakCount + 1, sourceSnapshot.LineCount)); throw new InvalidOperationException(Strings.InvalidLineCountCalculation); } return(new ElisionMap(newRoot, this.spanCount)); }
public void SubjectBuffersConnected( ITextView textView, ConnectionReason reason, IReadOnlyCollection <ITextBuffer> subjectBuffers) { IntellisenseManager manager = textView.Properties.GetOrCreateSingletonProperty( delegate { return(new IntellisenseManager(this, textView)); }); // Create the appropriate Intellisense controllers for the content types in the buffer graph. It's important that we do // this after creating the brokers, as the controllers will most likely start using the brokers immediately. for (int f = 0; f < this.IntellisenseControllerFactories.Count; ++f) { var factory = this.IntellisenseControllerFactories[f]; // filter subject buffers to get the ones that match the factory content types FrugalList <ITextBuffer> matchingSubjectBuffers = new FrugalList <ITextBuffer>(); foreach (string factoryContentType in factory.Metadata.ContentTypes) { foreach (ITextBuffer subjectBuffer in subjectBuffers) { if (subjectBuffer.ContentType.IsOfType(factoryContentType) && !matchingSubjectBuffers.Contains(subjectBuffer)) { matchingSubjectBuffers.Add(subjectBuffer); } } } if (matchingSubjectBuffers.Count > 0) { // This controller factory is registered for the content type we understand. Go ahead and create // one. Note that this won't give us a handle to a controller object. We wouldn't be able to do anything // with such a reference anyway. if (manager.Controllers[f] == null) { manager.Controllers[f] = this.GuardedOperations.InstantiateExtension (factory, factory, provider => provider.TryCreateIntellisenseController(textView, matchingSubjectBuffers)); } else { foreach (ITextBuffer matchingSubjectBuffer in matchingSubjectBuffers) { manager.Controllers[f].ConnectSubjectBuffer(matchingSubjectBuffer); } } } } }
} //For unit tests private void AddSpan(object key, PersistentSpan persistentSpan) { lock (_spansOnDocuments) { FrugalList <PersistentSpan> spans; if (!_spansOnDocuments.TryGetValue(key, out spans)) { this.EnsureEventsHooked(); spans = new FrugalList <PersistentSpan>(); _spansOnDocuments.Add(key, spans); } spans.Add(persistentSpan); } }
private Span MapNullSpansToSourceSnapshots(IElisionSnapshot elisionSnapshot, Span span, FrugalList <SnapshotSpan> result) { // TODO: this is identical to projection snapshot; can it be shared? FrugalList <SnapshotPoint> points = MapInsertionPointToSourceSnapshots(elisionSnapshot, span.Start); for (int p = 0; p < points.Count; ++p) { SnapshotPoint point = points[p]; SnapshotSpan mappedSpan = new SnapshotSpan(point.Snapshot, point.Position, 0); if (result.Count == 0 || mappedSpan != result[result.Count - 1]) { result.Add(mappedSpan); } } return(span); }
private void AddMapping(KeyState keyState, KeyInput keyInput, string text) { _keyStateToVimKeyDataMap[keyState] = new VimKeyData(keyInput, text); FrugalList<KeyState> list; if (!_keyInputToWpfKeyDataMap.TryGetValue(keyInput, out list)) { _keyInputToWpfKeyDataMap[keyInput] = new FrugalList<KeyState>(keyState); } else { list.Add(keyState); } }