//
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
//
// This file contain implementations details that are subject to change without notice.
// Use at your own risk.
//
namespace Microsoft.VisualStudio.Text.Operations.Implementation
{
using System;
using System.Diagnostics;
using Microsoft.VisualStudio.Utilities;
///
/// Default Text Navigation helper.
///
internal class DefaultTextNavigator : ITextStructureNavigator
{
#region Private Members
ITextBuffer _textBuffer;
IContentTypeRegistryService _contentTypeRegistry;
#endregion // Private Members
///
/// Keep the constructor internal so that only the factory can instantiate our class.
///
///
/// The text buffer that we will navigate on.
///
///
/// The registry for s.
///
internal DefaultTextNavigator(ITextBuffer textBuffer, IContentTypeRegistryService contentTypeRegistry)
{
// Verify
Debug.Assert(textBuffer != null);
Debug.Assert(contentTypeRegistry != null);
_textBuffer = textBuffer;
_contentTypeRegistry = contentTypeRegistry;
}
#region ITextStructureNavigator Members
///
/// Get the extent of the word at the given position. IsSignificant for the extent should be set to false for words
/// consisting of whitespace, unless the whitespace is a significant part of the document. If the
/// returned extent is insignificant whitespace, it should include all of the adjacent whitespace,
/// including newline characters, spaces, and tabs.
///
///
/// The text position anywhere in the word whose extents are needed.
///
///
/// A describing the word. IsSignificant will be set to false for whitespace or other
/// insignificant 'words' that should be ignored during navigation.
///
/// is less than 0 or greater than the length of the text.
public TextExtent GetExtentOfWord(SnapshotPoint currentPosition)
{
if (currentPosition.Snapshot.TextBuffer != _textBuffer)
{
throw new ArgumentException("currentPosition TextBuffer does not match to the current TextBuffer");
}
if (currentPosition.Position >= currentPosition.Snapshot.Length - 1)
{
// End of document
return new TextExtent(new SnapshotSpan(currentPosition,
currentPosition.Snapshot.Length - currentPosition),
true);
}
else
{
return new TextExtent(new SnapshotSpan(currentPosition, 1), true);
}
}
///
/// Get the span of the enclosing syntactic element given the currently active span.
///
///
/// The active span from where to get the span of the enclosing syntactic element.
///
///
/// A describing the enclosing syntactic element. If the given active
/// span covers multiple syntactic elements, then the least common ancestor of the elements
/// will be returned. If it already covers the root element of the document (a.k.a the whole document),
/// then a of the same span will be returned.
///
public SnapshotSpan GetSpanOfEnclosing(SnapshotSpan activeSpan)
{
if (activeSpan.IsEmpty && (activeSpan.Start != activeSpan.Snapshot.Length))
{
return new SnapshotSpan(activeSpan.Start, 1);
}
return new SnapshotSpan(activeSpan.Snapshot, 0, activeSpan.Snapshot.Length);
}
///
/// Get the span of the first child syntactic element given the currently active span.
/// If the active span has zero length, then the default behavior would be the same to
/// GetExtentOfEnclosingParent.
///
///
/// The active span from where to get the span of the first child syntactic element.
///
///
/// A describing the first child syntactic element. If the given active
/// span covers multiple syntactic elements, then the span of the least common ancestor of
/// the elements will be returned. If it already covers the leaf level element of the document,
/// then a of the same span will be returned.
/// (such that, when the same size span returned, we will try get the extent of its enclosing
/// parent, which, for the third case above, will be the whole document or the whole syntactic
/// element depend on where the span lies).
///
public SnapshotSpan GetSpanOfFirstChild(SnapshotSpan activeSpan)
{
if (activeSpan.IsEmpty)
{
return this.GetSpanOfEnclosing(activeSpan);
}
if (activeSpan.Length > 0 && activeSpan.Length < activeSpan.Snapshot.Length)
{
return new SnapshotSpan(activeSpan.Snapshot, 0, activeSpan.Snapshot.Length);
}
return new SnapshotSpan(activeSpan.Snapshot, 0, 1);
}
///
/// Get the span of the next sibling syntactic element given the currently active span. If the
/// active span has zero length, then the default behavior would be the same to
/// GetExtentOfEnclosingParent.
///
///
/// The active span from where to get the span of the next sibling syntactic element.
///
///
/// A describing the next sibling syntactic element. If the given active
/// span covers multiple syntactic elements, then the span of the next sibling element will be
/// returned. If text covered by the span doesn't followed by a sibling, then the default
/// behavior would be the same to GetExtentOfEnclosingParent.
///
public SnapshotSpan GetSpanOfNextSibling(SnapshotSpan activeSpan)
{
if (activeSpan.IsEmpty)
{
return this.GetSpanOfEnclosing(activeSpan);
}
if (activeSpan.End == activeSpan.Snapshot.Length)
{
return new SnapshotSpan(activeSpan.Snapshot, 0, activeSpan.Snapshot.Length);
}
return new SnapshotSpan(activeSpan.End, 1);
}
///
/// Get the span of the previous sibling syntactic element given the currently active span.
/// If the active span has zero length, then the default behavior would be the same to
/// GetExtentOfEnclosingParent.
///
///
/// The active span from where to get the span of the previous sibling syntactic element.
///
///
/// A describing the next sibling syntactic element. If the given active
/// span covers multiple syntactic elements, then the span of the previous element will be
/// returned. If text covered by the span doesn't preceded by a sibling, then the default
/// behavior would be the same to GetExtentOfEnclosingParent.
///
public SnapshotSpan GetSpanOfPreviousSibling(SnapshotSpan activeSpan)
{
if (activeSpan.IsEmpty)
{
return this.GetSpanOfEnclosing(activeSpan);
}
if (activeSpan.Start == 0)
{
return new SnapshotSpan(activeSpan.Snapshot, 0, activeSpan.Snapshot.Length);
}
return new SnapshotSpan(activeSpan.Start - 1, 1);
}
///
/// The content type that this navigator supports.
///
public IContentType ContentType
{
get
{
return _contentTypeRegistry.UnknownContentType;
}
}
#endregion // ITextStructureNavigator Members
}
}