Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/microsoft/vs-editor-api.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/Text/Impl/TextModel/PersistentSpanFactory.cs')
-rw-r--r--src/Text/Impl/TextModel/PersistentSpanFactory.cs256
1 files changed, 82 insertions, 174 deletions
diff --git a/src/Text/Impl/TextModel/PersistentSpanFactory.cs b/src/Text/Impl/TextModel/PersistentSpanFactory.cs
index 6ea3a3d..7e62ae1 100644
--- a/src/Text/Impl/TextModel/PersistentSpanFactory.cs
+++ b/src/Text/Impl/TextModel/PersistentSpanFactory.cs
@@ -7,14 +7,8 @@
//
namespace Microsoft.VisualStudio.Text.Implementation
{
- using Microsoft.VisualStudio.Text;
- using Microsoft.VisualStudio.Utilities;
- using Microsoft.VisualStudio.Text.Utilities;
- using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
- using System.Diagnostics;
- using System.IO;
[Export(typeof(IPersistentSpanFactory))]
internal class PersistentSpanFactory : IPersistentSpanFactory
@@ -22,17 +16,13 @@ namespace Microsoft.VisualStudio.Text.Implementation
[Import]
internal ITextDocumentFactoryService TextDocumentFactoryService;
- private readonly Dictionary<object, FrugalList<PersistentSpan>> _spansOnDocuments = new Dictionary<object, FrugalList<PersistentSpan>>(); //Used for lock
-
+ private readonly Dictionary<object, PersistentSpanSet> _spansOnDocuments = new Dictionary<object, PersistentSpanSet>(); //Used for lock
private bool _eventsHooked;
#region IPersistentSpanFactory members
public bool CanCreate(ITextBuffer buffer)
{
- if (buffer == null)
- {
- throw new ArgumentNullException("buffer");
- }
+ Requires.NotNull(buffer, nameof(buffer));
ITextDocument document;
return this.TextDocumentFactoryService.TryGetTextDocument(buffer, out document);
@@ -40,14 +30,16 @@ namespace Microsoft.VisualStudio.Text.Implementation
public IPersistentSpan Create(SnapshotSpan span, SpanTrackingMode trackingMode)
{
+ Requires.NotNull(span.Snapshot, nameof(span.Snapshot));
+
ITextDocument document;
if (this.TextDocumentFactoryService.TryGetTextDocument(span.Snapshot.TextBuffer, out document))
{
- PersistentSpan persistentSpan = new PersistentSpan(document, span, trackingMode, this);
-
- this.AddSpan(document, persistentSpan);
-
- return persistentSpan;
+ lock (_spansOnDocuments)
+ {
+ var spanSet = this.GetOrCreateSpanSet(null, document);
+ return spanSet.Create(span, trackingMode);
+ }
}
return null;
@@ -55,21 +47,21 @@ namespace Microsoft.VisualStudio.Text.Implementation
public IPersistentSpan Create(ITextSnapshot snapshot, int startLine, int startIndex, int endLine, int endIndex, SpanTrackingMode trackingMode)
{
+ Requires.NotNull(snapshot, nameof(snapshot));
+ Requires.Argument(startLine >= 0, nameof(startLine), "Must be non-negative.");
+ Requires.Argument(startIndex >= 0, nameof(startIndex), "Must be non-negative.");
+ Requires.Argument(endLine >= startLine, nameof(endLine), "Must be >= startLine.");
+ Requires.Argument((endIndex >= 0) && ((startLine != endLine) || (endIndex >= startIndex)), nameof(endIndex), "Must be non-negative and (endLine,endIndex) may not be before (startLine,startIndex).");
+ Requires.Range(((int)trackingMode >= (int)SpanTrackingMode.EdgeExclusive) || ((int)trackingMode <= (int)(SpanTrackingMode.EdgeNegative)), nameof(trackingMode));
+
ITextDocument document;
if (this.TextDocumentFactoryService.TryGetTextDocument(snapshot.TextBuffer, out document))
{
- var start = PersistentSpan.LineIndexToSnapshotPoint(startLine, startIndex, snapshot);
- var end = PersistentSpan.LineIndexToSnapshotPoint(endLine, endIndex, snapshot);
- if (end < start)
+ lock (_spansOnDocuments)
{
- end = start;
+ var spanSet = this.GetOrCreateSpanSet(null, document);
+ return spanSet.Create(snapshot, startLine, startIndex, endLine, endIndex, trackingMode);
}
-
- PersistentSpan persistentSpan = new PersistentSpan(document, new SnapshotSpan(start, end), trackingMode, this);
-
- this.AddSpan(document, persistentSpan);
-
- return persistentSpan;
}
return null;
@@ -77,218 +69,134 @@ namespace Microsoft.VisualStudio.Text.Implementation
public IPersistentSpan Create(string filePath, int startLine, int startIndex, int endLine, int endIndex, SpanTrackingMode trackingMode)
{
- if (string.IsNullOrEmpty(filePath))
- {
- throw new ArgumentException("filePath");
- }
- if (startLine < 0)
- {
- throw new ArgumentOutOfRangeException("startLine", "Must be non-negative.");
- }
- if (startIndex < 0)
- {
- throw new ArgumentOutOfRangeException("startIndex", "Must be non-negative.");
- }
- if (endLine < startLine)
- {
- throw new ArgumentOutOfRangeException("endLine", "Must be >= startLine.");
- }
- if ((endIndex < 0) || ((startLine == endLine) && (endIndex < startIndex)))
- {
- throw new ArgumentOutOfRangeException("endIndex", "Must be non-negative and (endLine,endIndex) may not be before (startLine,startIndex).");
- }
- if (((int)trackingMode < (int)SpanTrackingMode.EdgeExclusive) || ((int)trackingMode > (int)(SpanTrackingMode.EdgeNegative)))
+ Requires.NotNullOrEmpty(filePath, nameof(filePath));
+ Requires.Argument(startLine >= 0, nameof(startLine), "Must be non-negative.");
+ Requires.Argument(startIndex >= 0, nameof(startIndex), "Must be non-negative.");
+ Requires.Argument(endLine >= startLine, nameof(endLine), "Must be >= startLine.");
+ Requires.Argument((endIndex >= 0) && ((startLine != endLine) || (endIndex >= startIndex)), nameof(endIndex), "Must be non-negative and (endLine,endIndex) may not be before (startLine,startIndex).");
+ Requires.Range(((int)trackingMode >= (int)SpanTrackingMode.EdgeExclusive) || ((int)trackingMode <= (int)(SpanTrackingMode.EdgeNegative)), nameof(trackingMode));
+
+ var key = new FileNameKey(filePath);
+ lock (_spansOnDocuments)
{
- throw new ArgumentOutOfRangeException("trackingMode");
+ var spanSet = this.GetOrCreateSpanSet(key, null);
+ return spanSet.Create(startLine, startIndex, endLine, endIndex, trackingMode);
}
-
- PersistentSpan persistentSpan = new PersistentSpan(filePath, startLine, startIndex, endLine, endIndex, trackingMode, this);
-
- this.AddSpan(new FileNameKey(filePath), persistentSpan);
-
- return persistentSpan;
}
public IPersistentSpan Create(string filePath, Span span, SpanTrackingMode trackingMode)
{
- if (string.IsNullOrEmpty(filePath))
- {
- throw new ArgumentException("filePath");
- }
- if (((int)trackingMode < (int)SpanTrackingMode.EdgeExclusive) || ((int)trackingMode > (int)(SpanTrackingMode.EdgeNegative)))
+ Requires.NotNullOrEmpty(filePath, nameof(filePath));
+ Requires.Range(((int)trackingMode >= (int)SpanTrackingMode.EdgeExclusive) || ((int)trackingMode <= (int)(SpanTrackingMode.EdgeNegative)), nameof(trackingMode));
+
+ var key = new FileNameKey(filePath);
+ lock (_spansOnDocuments)
{
- throw new ArgumentOutOfRangeException("trackingMode");
+ var spanSet = this.GetOrCreateSpanSet(key, null);
+ return spanSet.Create(span, trackingMode);
}
-
- PersistentSpan persistentSpan = new PersistentSpan(filePath, span, trackingMode, this);
-
- this.AddSpan(new FileNameKey(filePath), persistentSpan);
-
- return persistentSpan;
}
#endregion
- internal bool IsEmpty { get { return _spansOnDocuments.Count == 0; } } //For unit tests
+ internal bool IsEmpty { get { return _spansOnDocuments.Count == 0; } } //For unit tests
- private void AddSpan(object key, PersistentSpan persistentSpan)
+ private PersistentSpanSet GetOrCreateSpanSet(FileNameKey filePath, ITextDocument document)
{
- lock (_spansOnDocuments)
+ object key = ((object)document) ?? filePath;
+ if (!_spansOnDocuments.TryGetValue(key, out PersistentSpanSet spanSet))
{
- FrugalList<PersistentSpan> spans;
- if (!_spansOnDocuments.TryGetValue(key, out spans))
+ if (!_eventsHooked)
{
- this.EnsureEventsHooked();
+ _eventsHooked = true;
- spans = new FrugalList<PersistentSpan>();
- _spansOnDocuments.Add(key, spans);
+ this.TextDocumentFactoryService.TextDocumentCreated += OnTextDocumentCreated;
+ this.TextDocumentFactoryService.TextDocumentDisposed += OnTextDocumentDisposed;
}
- spans.Add(persistentSpan);
+ spanSet = new PersistentSpanSet(filePath, document, this);
+ _spansOnDocuments.Add(key, spanSet);
}
- }
-
- private void EnsureEventsHooked()
- {
- if (!_eventsHooked)
- {
- _eventsHooked = true;
- this.TextDocumentFactoryService.TextDocumentCreated += OnTextDocumentCreated;
- this.TextDocumentFactoryService.TextDocumentDisposed += OnTextDocumentDisposed;
- }
+ return spanSet;
}
private void OnTextDocumentCreated(object sender, TextDocumentEventArgs e)
{
var path = new FileNameKey(e.TextDocument.FilePath);
- FrugalList<PersistentSpan> spans;
lock (_spansOnDocuments)
{
- if (_spansOnDocuments.TryGetValue(path, out spans))
+ if (_spansOnDocuments.TryGetValue(path, out PersistentSpanSet spanSet))
{
- foreach (var span in spans)
- {
- span.DocumentReopened(e.TextDocument);
- }
+ spanSet.DocumentReopened(e.TextDocument);
_spansOnDocuments.Remove(path);
- _spansOnDocuments.Add(e.TextDocument, spans);
+ _spansOnDocuments.Add(e.TextDocument, spanSet);
}
}
}
private void OnTextDocumentDisposed(object sender, TextDocumentEventArgs e)
{
- FrugalList<PersistentSpan> spans;
lock (_spansOnDocuments)
{
- if (_spansOnDocuments.TryGetValue(e.TextDocument, out spans))
+ if (_spansOnDocuments.TryGetValue(e.TextDocument, out PersistentSpanSet spanSet))
{
- foreach (var span in spans)
- {
- span.DocumentClosed();
- }
-
+ spanSet.DocumentClosed();
_spansOnDocuments.Remove(e.TextDocument);
- var path = new FileNameKey(e.TextDocument.FilePath);
- FrugalList<PersistentSpan> existingSpansOnPath;
- if (_spansOnDocuments.TryGetValue(path, out existingSpansOnPath))
+ if (_spansOnDocuments.TryGetValue(spanSet.FileKey, out PersistentSpanSet existingSpansOnPath))
{
- //Handle (badly) the case where a document is renamed to an existing closed document & then closed.
- existingSpansOnPath.AddRange(spans);
+ // Handle (badly) the case where a document is renamed to an existing closed document & then closed.
+ // We should only end up in this case if we had spans on two open documents that were both renamed
+ // to the same file name & then closed.
+ foreach (var s in spanSet.Spans)
+ {
+ s.SetSpanSet(existingSpansOnPath);
+ existingSpansOnPath.Spans.Add(s);
+ }
+
+ spanSet.Spans.Clear();
+ spanSet.Dispose();
}
else
{
- _spansOnDocuments.Add(path, spans);
+ _spansOnDocuments.Add(spanSet.FileKey, spanSet);
}
}
}
}
- internal void Delete(PersistentSpan span)
+ internal void DocumentRenamed(PersistentSpanSet spanSet)
{
lock (_spansOnDocuments)
{
- ITextDocument document = span.Document;
- if (document != null)
+ if (_spansOnDocuments.TryGetValue(spanSet.FileKey, out PersistentSpanSet existingSpansOnPath))
{
- FrugalList<PersistentSpan> spans;
- if (_spansOnDocuments.TryGetValue(document, out spans))
+ // There were spans on a closed document with the same name as this one. Move all of those spans to this one
+ // and "open" them (note that this will probably do bad things to their positions but it is the best we
+ // can do).
+ foreach (var s in existingSpansOnPath.Spans)
{
- spans.Remove(span);
+ s.SetSpanSet(spanSet);
+ spanSet.Spans.Add(s);
- if (spans.Count == 0)
- {
- //Last one ... remove all references to document.
- _spansOnDocuments.Remove(document);
- }
+ s.DocumentReopened();
}
- else
- {
- Debug.Fail("There should have been an entry in SpanOnDocuments.");
- }
- }
- else
- {
- var path = new FileNameKey(span.FilePath);
- FrugalList<PersistentSpan> spans;
- if (_spansOnDocuments.TryGetValue(path, out spans))
- {
- spans.Remove(span);
- if (spans.Count == 0)
- {
- //Last one ... remove all references to path.
- _spansOnDocuments.Remove(path);
- }
- }
- else
- {
- Debug.Fail("There should have been an entry in SpanOnDocuments.");
- }
+ existingSpansOnPath.Spans.Clear();
+ existingSpansOnPath.Dispose();
}
}
}
-
- private class FileNameKey
+ internal void Delete(PersistentSpanSet spanSet, PersistentSpan span)
{
- private readonly string _fileName;
- private readonly int _hashCode;
-
- public FileNameKey(string fileName)
+ lock (_spansOnDocuments)
{
- //Gracefully catch errors getting the full path (which can happen if the file name is on a protected share).
- try
+ if (spanSet.Spans.Remove(span) && (spanSet.Spans.Count == 0))
{
- _fileName = Path.GetFullPath(fileName);
+ _spansOnDocuments.Remove(((object)(spanSet.Document)) ?? spanSet.FileKey);
+ spanSet.Dispose();
}
- catch
- {
- //This shouldn't happen (we are generally passed names associated with documents that we are expecting to open so
- //we should have access). If we fail, we will, at worst not get the same underlying document when people create
- //persistent spans using unnormalized names.
- _fileName = fileName;
- }
-
- _hashCode = StringComparer.OrdinalIgnoreCase.GetHashCode(_fileName);
- }
-
- //Override equality and hash code
- public override int GetHashCode()
- {
- return _hashCode;
- }
-
- public override bool Equals(object obj)
- {
- var other = obj as FileNameKey;
- return (other != null) && string.Equals(_fileName, other._fileName, StringComparison.OrdinalIgnoreCase);
- }
-
- public override string ToString()
- {
- return _fileName;
}
}
}