Example #1
0
 /// <inheritdoc/>
 public override int GetNextCaretPosition(int visualColumn, LogicalDirection direction, CaretPositioningMode mode)
 {
     int textOffset = parentVisualLine.StartOffset + this.RelativeTextOffset;
     int pos = TextUtilities.GetNextCaretPosition(parentVisualLine.Document, textOffset + visualColumn - this.VisualColumn, direction, mode);
     if (pos < textOffset || pos > textOffset + this.DocumentLength)
         return -1;
     else
         return this.VisualColumn + pos - textOffset;
 }
			public override int GetNextCaretPosition(int visualColumn, LogicalDirection direction, CaretPositioningMode mode)
			{
				// only place a caret stop before the newline, no caret stop after it
				if (visualColumn > this.VisualColumn && direction == LogicalDirection.Backward ||
				    visualColumn < this.VisualColumn && direction == LogicalDirection.Forward)
				{
					return this.VisualColumn;
				} else {
					return -1;
				}
			}
        /// <summary>
        /// Gets the next caret position inside this element.
        /// </summary>
        /// <param name="visualColumn">The visual column from which the search should be started.</param>
        /// <param name="direction">The search direction (forwards or backwards).</param>
        /// <param name="mode">Whether to stop only at word borders.</param>
        /// <returns>The visual column of the next caret position, or -1 if there is no next caret position.</returns>
        /// <remarks>
        /// In the space between two line elements, it is sufficient that one of them contains a caret position;
        /// though in many cases, both of them contain one.
        /// </remarks>
        public virtual int GetNextCaretPosition(int visualColumn, LogicalDirection direction, CaretPositioningMode mode)
        {
            int stop1 = this.VisualColumn;
            int stop2 = this.VisualColumn + this.VisualLength;

            if (direction == LogicalDirection.Backward)
            {
                if (visualColumn > stop2 && mode != CaretPositioningMode.WordStart && mode != CaretPositioningMode.WordStartOrSymbol)
                {
                    return(stop2);
                }
                else if (visualColumn > stop1)
                {
                    return(stop1);
                }
            }
            else
            {
                if (visualColumn < stop1)
                {
                    return(stop1);
                }
                else if (visualColumn < stop2 && mode != CaretPositioningMode.WordStart && mode != CaretPositioningMode.WordStartOrSymbol)
                {
                    return(stop2);
                }
            }
            return(-1);
        }
Example #4
0
        /// <summary>
        /// Gets the next caret position inside this element.
        /// </summary>
        /// <param name="visualColumn">The visual column from which the search should be started.</param>
        /// <param name="direction">The search direction (forwards or backwards).</param>
        /// <param name="mode">Whether to stop only at word borders.</param>
        /// <returns>The visual column of the next caret position, or -1 if there is no next caret position.</returns>
        /// <remarks>
        /// In the space between two line elements, it is sufficient that one of them contains a caret position;
        /// though in many cases, both of them contain one.
        /// </remarks>
        public virtual int GetNextCaretPosition(int visualColumn, LogicalDirection direction, CaretPositioningMode mode)
        {
            int stop1 = VisualColumn;
            int stop2 = VisualColumn + VisualLength;

            if (direction == LogicalDirection.Backward)
            {
                if (visualColumn > stop2 && mode != CaretPositioningMode.WordStart && mode != CaretPositioningMode.WordStartOrSymbol)
                    return stop2;
                else if (visualColumn > stop1)
                    return stop1;
            }
            else
            {
                if (visualColumn < stop1)
                    return stop1;
                else if (visualColumn < stop2 && mode != CaretPositioningMode.WordStart && mode != CaretPositioningMode.WordStartOrSymbol)
                    return stop2;
            }
            return -1;
        }
			public override int GetNextCaretPosition(int visualColumn, bool backwords, CaretPositioningMode mode)
			{
				return base.GetNextCaretPosition(visualColumn, backwords, mode);
			}
 static void MoveCaretRight(TextArea textArea, TextViewPosition caretPosition, VisualLine visualLine, CaretPositioningMode mode)
 {
     int pos = visualLine.GetNextCaretPosition(caretPosition.VisualColumn, LogicalDirection.Forward, mode);
     if (pos >= 0) {
         SetCaretPosition(textArea, pos, visualLine.GetRelativeOffset(pos) + visualLine.FirstDocumentLine.Offset);
     } else {
         // move to start of next line
         DocumentLine nextDocumentLine = visualLine.LastDocumentLine.NextLine;
         if (nextDocumentLine != null) {
             VisualLine nextLine = textArea.TextView.GetOrConstructVisualLine(nextDocumentLine);
             pos = nextLine.GetNextCaretPosition(-1, LogicalDirection.Forward, mode);
             if (pos < 0)
                 throw ThrowUtil.NoValidCaretPosition();
             SetCaretPosition(textArea, pos, nextLine.GetRelativeOffset(pos) + nextLine.FirstDocumentLine.Offset);
         } else {
             // at end of document
             Debug.Assert(visualLine.LastDocumentLine.Offset + visualLine.LastDocumentLine.TotalLength == textArea.Document.TextLength);
             SetCaretPosition(textArea, -1, textArea.Document.TextLength);
         }
     }
 }
Example #7
0
		static bool IsNormal(CaretPositioningMode mode)
		{
			return mode == CaretPositioningMode.Normal || mode == CaretPositioningMode.EveryCodepoint;
		}
Example #8
0
 private static bool HasStopsInVirtualSpace(CaretPositioningMode mode)
 {
     return(mode == CaretPositioningMode.Normal || mode == CaretPositioningMode.EveryCodepoint);
 }
Example #9
0
		public int GetNextCaretPosition(int visualColumn, bool backwords, CaretPositioningMode mode) 
		{ 
			//TODO: VisualLine.GetNextCaretPosition()
			throw new NotImplementedException();
		}
Example #10
0
        /// <summary>
        /// Gets the next possible caret position after visualColumn, or -1 if there is no caret position.
        /// </summary>
        public int GetNextCaretPosition(int visualColumn, LogicalDirection direction, CaretPositioningMode mode, bool allowVirtualSpace)
        {
            if (!HasStopsInVirtualSpace(mode))
                allowVirtualSpace = false;

            if (elements.Count == 0) {
                // special handling for empty visual lines:
                if (allowVirtualSpace) {
                    if (direction == LogicalDirection.Forward)
                        return Math.Max(0, visualColumn + 1);
                    else if (visualColumn > 0)
                        return visualColumn - 1;
                    else
                        return -1;
                } else {
                    // even though we don't have any elements,
                    // there's a single caret stop at visualColumn 0
                    if (visualColumn < 0 && direction == LogicalDirection.Forward)
                        return 0;
                    else if (visualColumn > 0 && direction == LogicalDirection.Backward)
                        return 0;
                    else
                        return -1;
                }
            }

            int i;
            if (direction == LogicalDirection.Backward) {
                // Search Backwards:
                // If the last element doesn't handle line borders, return the line end as caret stop

                if (visualColumn > this.VisualLength && !elements[elements.Count-1].HandlesLineBorders && HasImplicitStopAtLineEnd(mode)) {
                    if (allowVirtualSpace)
                        return visualColumn - 1;
                    else
                        return this.VisualLength;
                }
                // skip elements that start after or at visualColumn
                for (i = elements.Count - 1; i >= 0; i--) {
                    if (elements[i].VisualColumn < visualColumn)
                        break;
                }
                // search last element that has a caret stop
                for (; i >= 0; i--) {
                    int pos = elements[i].GetNextCaretPosition(
                        Math.Min(visualColumn, elements[i].VisualColumn + elements[i].VisualLength + 1),
                        direction, mode);
                    if (pos >= 0)
                        return pos;
                }
                // If we've found nothing, and the first element doesn't handle line borders,
                // return the line start as normal caret stop.
                if (visualColumn > 0 && !elements[0].HandlesLineBorders && HasImplicitStopAtLineStart(mode))
                    return 0;
            } else {
                // Search Forwards:
                // If the first element doesn't handle line borders, return the line start as caret stop
                if (visualColumn < 0 && !elements[0].HandlesLineBorders && HasImplicitStopAtLineStart(mode))
                    return 0;
                // skip elements that end before or at visualColumn
                for (i = 0; i < elements.Count; i++) {
                    if (elements[i].VisualColumn + elements[i].VisualLength > visualColumn)
                        break;
                }
                // search first element that has a caret stop
                for (; i < elements.Count; i++) {
                    int pos = elements[i].GetNextCaretPosition(
                        Math.Max(visualColumn, elements[i].VisualColumn - 1),
                        direction, mode);
                    if (pos >= 0)
                        return pos;
                }
                // if we've found nothing, and the last element doesn't handle line borders,
                // return the line end as caret stop
                if ((allowVirtualSpace || !elements[elements.Count-1].HandlesLineBorders) && HasImplicitStopAtLineEnd(mode)) {
                    if (visualColumn < this.VisualLength)
                        return this.VisualLength;
                    else if (allowVirtualSpace)
                        return visualColumn + 1;
                }
            }
            // we've found nothing, return -1 and let the caret search continue in the next line
            return -1;
        }
 private void ExpandToEnclosingUnit(CaretPositioningMode mode)
 {
     int start = TextUtilities.GetNextCaretPosition(doc, segment.Offset + 1, LogicalDirection.Backward, mode);
     if (start < 0)
         return;
     int end = TextUtilities.GetNextCaretPosition(doc, start, LogicalDirection.Forward, mode);
     if (end < 0)
         return;
     segment = new AnchorSegment(doc, start, end - start);
 }
Example #12
0
 static bool HasImplicitStopAtLineStart(CaretPositioningMode mode)
 {
     return(mode == CaretPositioningMode.Normal);
 }
Example #13
0
 static bool HasImplicitStopAtLineEnd(CaretPositioningMode mode)
 {
     return(true);
 }
Example #14
0
        /// <summary>
        /// Gets the next possible caret position after visualColumn, or -1 if there is no caret position.
        /// </summary>
        public int GetNextCaretPosition(int visualColumn, LogicalDirection direction, CaretPositioningMode mode)
        {
            if (elements.Count == 0)
            {
                // special handling for empty visual lines:
                // even though we don't have any elements,
                // there's a single caret stop at visualColumn 0
                if (visualColumn < 0 && direction == LogicalDirection.Forward)
                {
                    return(0);
                }
                else if (visualColumn > 0 && direction == LogicalDirection.Backward)
                {
                    return(0);
                }
                else
                {
                    return(-1);
                }
            }

            int i;

            if (direction == LogicalDirection.Backward)
            {
                // Search Backwards:
                // If the last element doesn't handle line borders, return the line end as caret stop

                if (visualColumn > this.VisualLength && !elements[elements.Count - 1].HandlesLineBorders && HasImplicitStopAtLineEnd(mode))
                {
                    return(this.VisualLength);
                }
                // skip elements that start after or at visualColumn
                for (i = elements.Count - 1; i >= 0; i--)
                {
                    if (elements[i].VisualColumn < visualColumn)
                    {
                        break;
                    }
                }
                // search last element that has a caret stop
                for (; i >= 0; i--)
                {
                    int pos = elements[i].GetNextCaretPosition(
                        Math.Min(visualColumn, elements[i].VisualColumn + elements[i].VisualLength + 1),
                        direction, mode);
                    if (pos >= 0)
                    {
                        return(pos);
                    }
                }
                // If we've found nothing, and the first element doesn't handle line borders,
                // return the line start as normal caret stop.
                if (visualColumn > 0 && !elements[0].HandlesLineBorders && HasImplicitStopAtLineStart(mode))
                {
                    return(0);
                }
            }
            else
            {
                // Search Forwards:
                // If the first element doesn't handle line borders, return the line start as caret stop
                if (visualColumn < 0 && !elements[0].HandlesLineBorders && HasImplicitStopAtLineStart(mode))
                {
                    return(0);
                }
                // skip elements that end before or at visualColumn
                for (i = 0; i < elements.Count; i++)
                {
                    if (elements[i].VisualColumn + elements[i].VisualLength > visualColumn)
                    {
                        break;
                    }
                }
                // search first element that has a caret stop
                for (; i < elements.Count; i++)
                {
                    int pos = elements[i].GetNextCaretPosition(
                        Math.Max(visualColumn, elements[i].VisualColumn - 1),
                        direction, mode);
                    if (pos >= 0)
                    {
                        return(pos);
                    }
                }
                // if we've found nothing, and the last element doesn't handle line borders,
                // return the line end as caret stop
                if (visualColumn < this.VisualLength && !elements[elements.Count - 1].HandlesLineBorders && HasImplicitStopAtLineEnd(mode))
                {
                    return(this.VisualLength);
                }
            }
            // we've found nothing, return -1 and let the caret search continue in the next line
            return(-1);
        }
 int GetPrevCaretStop(string text, int offset, CaretPositioningMode mode)
 {
     return(TextUtilities.GetNextCaretPosition(new StringTextSource(text), offset, LogicalDirection.Backward, mode));
 }
        /// <inheritdoc/>
        public override int GetNextCaretPosition(int visualColumn, LogicalDirection direction, CaretPositioningMode mode)
        {
            int textOffset = parentVisualLine.StartOffset + this.RelativeTextOffset;
            int pos        = TextUtilities.GetNextCaretPosition(parentVisualLine.Document, textOffset + visualColumn - this.VisualColumn, direction, mode);

            if (pos < textOffset || pos > textOffset + this.DocumentLength)
            {
                return(-1);
            }
            else
            {
                return(this.VisualColumn + pos - textOffset);
            }
        }
Example #17
0
        static TextViewPosition GetPrevCaretPosition(TextView textView, TextViewPosition caretPosition, VisualLine visualLine, CaretPositioningMode mode, bool enableVirtualSpace)
        {
            int pos = visualLine.GetNextCaretPosition(caretPosition.VisualColumn, LogicalDirection.Backward, mode, enableVirtualSpace);

            if (pos >= 0)
            {
                return(visualLine.GetTextViewPosition(pos));
            }
            var previousDocumentLine = visualLine.FirstDocumentLine.PreviousLine;

            if (previousDocumentLine != null)
            {
                var previousLine = textView.GetOrConstructVisualLine(previousDocumentLine);
                pos = previousLine.GetNextCaretPosition(previousLine.VisualLength + 1, LogicalDirection.Backward, mode, enableVirtualSpace);
                return(previousLine.GetTextViewPosition(pos));
            }
            return(new TextViewPosition(0, 0));
        }
Example #18
0
 private static bool HasImplicitStopAtLineStart(CaretPositioningMode mode)
 {
     return(mode == CaretPositioningMode.Normal || mode == CaretPositioningMode.EveryCodepoint);
 }
Example #19
0
 static bool HasImplicitStopAtLineStart(CaretPositioningMode mode)
 {
     return mode == CaretPositioningMode.Normal;
 }
        static void MoveCaretRight(TextArea textArea, TextViewPosition caretPosition, VisualLine visualLine, CaretPositioningMode mode)
        {
            int pos = visualLine.GetNextCaretPosition(caretPosition.VisualColumn, LogicalDirection.Forward, mode, textArea.Selection.EnableVirtualSpace);

            if (pos >= 0)
            {
                SetCaretPosition(textArea, pos, visualLine.GetRelativeOffset(pos) + visualLine.FirstDocumentLine.Offset);
            }
            else
            {
                // move to start of next line
                DocumentLine nextDocumentLine = visualLine.LastDocumentLine.NextLine;
                if (nextDocumentLine != null)
                {
                    VisualLine nextLine = textArea.TextView.GetOrConstructVisualLine(nextDocumentLine);
                    pos = nextLine.GetNextCaretPosition(-1, LogicalDirection.Forward, mode, textArea.Selection.EnableVirtualSpace);
                    if (pos < 0)
                    {
                        throw ThrowUtil.NoValidCaretPosition();
                    }
                    SetCaretPosition(textArea, pos, nextLine.GetRelativeOffset(pos) + nextLine.FirstDocumentLine.Offset);
                }
                else
                {
                    // at end of document
                    Debug.Assert(visualLine.LastDocumentLine.Offset + visualLine.LastDocumentLine.TotalLength == textArea.Document.TextLength);
                    SetCaretPosition(textArea, -1, textArea.Document.TextLength);
                }
            }
        }
Example #21
0
        /// <summary>
        /// Gets the next caret position.
        /// </summary>
        /// <param name="textSource">The text source.</param>
        /// <param name="offset">The start offset inside the text source.</param>
        /// <param name="direction">The search direction (forwards or backwards).</param>
        /// <param name="mode">The mode for caret positioning.</param>
        /// <returns>The offset of the next caret position, or -1 if there is no further caret position
        /// in the text source.</returns>
        /// <remarks>
        /// This method is NOT equivalent to the actual caret movement when using VisualLine.GetNextCaretPosition.
        /// In real caret movement, there are additional caret stops at line starts and ends. This method
        /// treats linefeeds as simple whitespace.
        /// </remarks>
        public static int GetNextCaretPosition(ITextSource textSource, int offset, LogicalDirection direction, CaretPositioningMode mode)
        {
            if (textSource == null)
                throw new ArgumentNullException(nameof(textSource));
            if (mode != CaretPositioningMode.Normal
                && mode != CaretPositioningMode.WordBorder
                && mode != CaretPositioningMode.WordStart
                && mode != CaretPositioningMode.WordBorderOrSymbol
                && mode != CaretPositioningMode.WordStartOrSymbol)
            {
                throw new ArgumentException("Unsupported CaretPositioningMode: " + mode, nameof(mode));
            }
            if (direction != LogicalDirection.Backward
                && direction != LogicalDirection.Forward)
            {
                throw new ArgumentException("Invalid LogicalDirection: " + direction, nameof(direction));
            }
            int textLength = textSource.TextLength;
            if (textLength <= 0)
            {
                // empty document? has a normal caret position at 0, though no word borders
                if (mode == CaretPositioningMode.Normal)
                {
                    if (offset > 0 && direction == LogicalDirection.Backward) return 0;
                    if (offset < 0 && direction == LogicalDirection.Forward) return 0;
                }
                return -1;
            }
            while (true)
            {
                int nextPos = (direction == LogicalDirection.Backward) ? offset - 1 : offset + 1;

                // return -1 if there is no further caret position in the text source
                // we also need this to handle offset values outside the valid range
                if (nextPos < 0 || nextPos > textLength)
                    return -1;

                // stop at every caret position? we can stop immediately.
                if (mode == CaretPositioningMode.Normal)
                    return nextPos;
                // not normal mode? we're looking for word borders...

                // check if we've run against the textSource borders.
                // a 'textSource' usually isn't the whole document, but a single VisualLineElement.
                if (nextPos == 0)
                {
                    // at the document start, there's only a word border
                    // if the first character is not whitespace
                    if (!char.IsWhiteSpace(textSource.GetCharAt(0)))
                        return nextPos;
                }
                else if (nextPos == textLength)
                {
                    // at the document end, there's never a word start
                    if (mode != CaretPositioningMode.WordStart && mode != CaretPositioningMode.WordStartOrSymbol)
                    {
                        // at the document end, there's only a word border
                        // if the last character is not whitespace
                        if (!char.IsWhiteSpace(textSource.GetCharAt(textLength - 1)))
                            return nextPos;
                    }
                }
                else
                {
                    CharacterClass charBefore = GetCharacterClass(textSource.GetCharAt(nextPos - 1));
                    CharacterClass charAfter = GetCharacterClass(textSource.GetCharAt(nextPos));
                    if (charBefore == charAfter)
                    {
                        if (charBefore == CharacterClass.Other &&
                            (mode == CaretPositioningMode.WordBorderOrSymbol || mode == CaretPositioningMode.WordStartOrSymbol))
                        {
                            // With the "OrSymbol" modes, there's a word border and start between any two unknown characters
                            return nextPos;
                        }
                    }
                    else
                    {
                        // this looks like a possible border

                        // if we're looking for word starts, check that this is a word start (and not a word end)
                        // if we're just checking for word borders, accept unconditionally
                        if (!((mode == CaretPositioningMode.WordStart || mode == CaretPositioningMode.WordStartOrSymbol)
                              && (charAfter == CharacterClass.Whitespace || charAfter == CharacterClass.LineTerminator)))
                        {
                            return nextPos;
                        }
                    }
                }
                // we'll have to continue searching...
                offset = nextPos;
            }
        }
        static void MoveCaretLeft(TextArea textArea, TextViewPosition caretPosition, VisualLine visualLine, CaretPositioningMode mode)
        {
            int pos = visualLine.GetNextCaretPosition(caretPosition.VisualColumn, LogicalDirection.Backward, mode, textArea.Selection.EnableVirtualSpace);

            if (pos >= 0)
            {
                SetCaretPosition(textArea, pos, visualLine.GetRelativeOffset(pos) + visualLine.FirstDocumentLine.Offset);
            }
            else
            {
                // move to end of previous line
                DocumentLine previousDocumentLine = visualLine.FirstDocumentLine.PreviousLine;
                if (previousDocumentLine != null)
                {
                    VisualLine previousLine = textArea.TextView.GetOrConstructVisualLine(previousDocumentLine);
                    pos = previousLine.GetNextCaretPosition(previousLine.VisualLength + 1, LogicalDirection.Backward, mode, textArea.Selection.EnableVirtualSpace);
                    if (pos < 0)
                    {
                        throw ThrowUtil.NoValidCaretPosition();
                    }
                    SetCaretPosition(textArea, pos, previousLine.GetRelativeOffset(pos) + previousLine.FirstDocumentLine.Offset);
                }
                else
                {
                    // at start of document
                    Debug.Assert(visualLine.FirstDocumentLine.Offset == 0);
                    SetCaretPosition(textArea, 0, 0);
                }
            }
        }
Example #23
0
		static bool HasImplicitStopAtLineStart(CaretPositioningMode mode)
		{
			return mode == CaretPositioningMode.Normal || mode == CaretPositioningMode.EveryCodepoint;
		}
Example #24
0
 public override int GetNextCaretPosition(int visualColumn, LogicalDirection direction, CaretPositioningMode mode)
 {
     if (mode == CaretPositioningMode.Normal || mode == CaretPositioningMode.EveryCodepoint)
     {
         return(base.GetNextCaretPosition(visualColumn, direction, mode));
     }
     else
     {
         return(-1);
     }
 }
 static void MoveCaretLeft(TextArea textArea, TextViewPosition caretPosition, VisualLine visualLine, CaretPositioningMode mode)
 {
     int pos = visualLine.GetNextCaretPosition(caretPosition.VisualColumn, LogicalDirection.Backward, mode);
     if (pos >= 0) {
         SetCaretPosition(textArea, pos, visualLine.GetRelativeOffset(pos) + visualLine.FirstDocumentLine.Offset);
     } else {
         // move to end of previous line
         DocumentLine previousDocumentLine = visualLine.FirstDocumentLine.PreviousLine;
         if (previousDocumentLine != null) {
             VisualLine previousLine = textArea.TextView.GetOrConstructVisualLine(previousDocumentLine);
             pos = previousLine.GetNextCaretPosition(previousLine.VisualLength + 1, LogicalDirection.Backward, mode);
             if (pos < 0)
                 throw ThrowUtil.NoValidCaretPosition();
             SetCaretPosition(textArea, pos, previousLine.GetRelativeOffset(pos) + previousLine.FirstDocumentLine.Offset);
         } else {
             // at start of document
             Debug.Assert(visualLine.FirstDocumentLine.Offset == 0);
             SetCaretPosition(textArea, 0, 0);
         }
     }
 }
Example #26
0
        static TextViewPosition GetNextCaretPosition(TextView textView, TextViewPosition caretPosition, VisualLine visualLine, CaretPositioningMode mode, bool enableVirtualSpace)
        {
            int pos = visualLine.GetNextCaretPosition(caretPosition.VisualColumn, LogicalDirection.Forward, mode, enableVirtualSpace);

            if (pos >= 0)
            {
                return(visualLine.GetTextViewPosition(pos));
            }
            else
            {
                // move to start of next line
                DocumentLine nextDocumentLine = visualLine.LastDocumentLine.NextLine;
                if (nextDocumentLine != null)
                {
                    VisualLine nextLine = textView.GetOrConstructVisualLine(nextDocumentLine);
                    pos = nextLine.GetNextCaretPosition(-1, LogicalDirection.Forward, mode, enableVirtualSpace);
                    if (pos < 0)
                    {
                        throw ThrowUtil.NoValidCaretPosition();
                    }
                    return(nextLine.GetTextViewPosition(pos));
                }
                else
                {
                    // at end of document
                    Debug.Assert(visualLine.LastDocumentLine.Offset + visualLine.LastDocumentLine.TotalLength == textView.Document.TextLength);
                    return(new TextViewPosition(textView.Document.GetLocation(textView.Document.TextLength)));
                }
            }
        }
Example #27
0
		/// <summary>
		/// Gets the next caret position.
		/// </summary>
		/// <param name="textSource">The text source.</param>
		/// <param name="offset">The start offset inside the text source.</param>
		/// <param name="direction">The search direction (forwards or backwards).</param>
		/// <param name="mode">The mode for caret positioning.</param>
		/// <returns>The offset of the next caret position, or -1 if there is no further caret position
		/// in the text source.</returns>
		/// <remarks>
		/// This method is NOT equivalent to the actual caret movement when using VisualLine.GetNextCaretPosition.
		/// In real caret movement, there are additional caret stops at line starts and ends. This method
		/// treats linefeeds as simple whitespace.
		/// </remarks>
		public static int GetNextCaretPosition(ITextSource textSource, int offset, LogicalDirection direction, CaretPositioningMode mode)
		{
			if (textSource == null)
				throw new ArgumentNullException("textSource");
			switch (mode) {
				case CaretPositioningMode.Normal:
				case CaretPositioningMode.EveryCodepoint:
				case CaretPositioningMode.WordBorder:
				case CaretPositioningMode.WordBorderOrSymbol:
				case CaretPositioningMode.WordStart:
				case CaretPositioningMode.WordStartOrSymbol:
					break; // OK
				default:
					throw new ArgumentException("Unsupported CaretPositioningMode: " + mode, "mode");
			}
			if (direction != LogicalDirection.Backward
			    && direction != LogicalDirection.Forward)
			{
				throw new ArgumentException("Invalid LogicalDirection: " + direction, "direction");
			}
			int textLength = textSource.TextLength;
			if (textLength <= 0) {
				// empty document? has a normal caret position at 0, though no word borders
				if (IsNormal(mode)) {
					if (offset > 0 && direction == LogicalDirection.Backward) return 0;
					if (offset < 0 && direction == LogicalDirection.Forward) return 0;
				}
				return -1;
			}
			while (true) {
				int nextPos = (direction == LogicalDirection.Backward) ? offset - 1 : offset + 1;
				
				// return -1 if there is no further caret position in the text source
				// we also need this to handle offset values outside the valid range
				if (nextPos < 0 || nextPos > textLength)
					return -1;
				
				// check if we've run against the textSource borders.
				// a 'textSource' usually isn't the whole document, but a single VisualLineElement.
				if (nextPos == 0) {
					// at the document start, there's only a word border
					// if the first character is not whitespace
					if (IsNormal(mode) || !char.IsWhiteSpace(textSource.GetCharAt(0)))
						return nextPos;
				} else if (nextPos == textLength) {
					// at the document end, there's never a word start
					if (mode != CaretPositioningMode.WordStart && mode != CaretPositioningMode.WordStartOrSymbol) {
						// at the document end, there's only a word border
						// if the last character is not whitespace
						if (IsNormal(mode) || !char.IsWhiteSpace(textSource.GetCharAt(textLength - 1)))
							return nextPos;
					}
				} else {
					char charBefore = textSource.GetCharAt(nextPos - 1);
					char charAfter = textSource.GetCharAt(nextPos);
					// Don't stop in the middle of a surrogate pair
					if (!char.IsSurrogatePair(charBefore, charAfter)) {
						CharacterClass classBefore = GetCharacterClass(charBefore);
						CharacterClass classAfter = GetCharacterClass(charAfter);
						// get correct class for characters outside BMP:
						if (char.IsLowSurrogate(charBefore) && nextPos >= 2) {
							classBefore = GetCharacterClass(textSource.GetCharAt(nextPos - 2), charBefore);
						}
						if (char.IsHighSurrogate(charAfter) && nextPos + 1 < textLength) {
							classAfter = GetCharacterClass(charAfter, textSource.GetCharAt(nextPos + 1));
						}
						if (StopBetweenCharacters(mode, classBefore, classAfter)) {
							return nextPos;
						}
					}
				}
				// we'll have to continue searching...
				offset = nextPos;
			}
		}
Example #28
0
        static TextViewPosition GetPrevCaretPosition(TextView textView, TextViewPosition caretPosition, VisualLine visualLine, CaretPositioningMode mode, bool enableVirtualSpace)
        {
            int pos = visualLine.GetNextCaretPosition(caretPosition.VisualColumn, LogicalDirection.Backward, mode, enableVirtualSpace);

            if (pos >= 0)
            {
                return(visualLine.GetTextViewPosition(pos));
            }
            else
            {
                // move to end of previous line
                DocumentLine previousDocumentLine = visualLine.FirstDocumentLine.PreviousLine;
                if (previousDocumentLine != null)
                {
                    VisualLine previousLine = textView.GetOrConstructVisualLine(previousDocumentLine);
                    pos = previousLine.GetNextCaretPosition(previousLine.VisualLength + 1, LogicalDirection.Backward, mode, enableVirtualSpace);
                    if (pos < 0)
                    {
                        throw ThrowUtil.NoValidCaretPosition();
                    }
                    return(previousLine.GetTextViewPosition(pos));
                }
                else
                {
                    // at start of document
                    Debug.Assert(visualLine.FirstDocumentLine.Offset == 0);
                    return(new TextViewPosition(0, 0));
                }
            }
        }
Example #29
0
		static bool StopBetweenCharacters(CaretPositioningMode mode, CharacterClass charBefore, CharacterClass charAfter)
		{
			if (mode == CaretPositioningMode.EveryCodepoint)
				return true;
			// Don't stop in the middle of a grapheme
			if (charAfter == CharacterClass.CombiningMark)
				return false;
			// Stop after every grapheme in normal mode
			if (mode == CaretPositioningMode.Normal)
				return true;
			if (charBefore == charAfter) {
				if (charBefore == CharacterClass.Other &&
				    (mode == CaretPositioningMode.WordBorderOrSymbol || mode == CaretPositioningMode.WordStartOrSymbol))
				{
					// With the "OrSymbol" modes, there's a word border and start between any two unknown characters
					return true;
				}
			} else {
				// this looks like a possible border
				
				// if we're looking for word starts, check that this is a word start (and not a word end)
				// if we're just checking for word borders, accept unconditionally
				if (!((mode == CaretPositioningMode.WordStart || mode == CaretPositioningMode.WordStartOrSymbol)
				      && (charAfter == CharacterClass.Whitespace || charAfter == CharacterClass.LineTerminator)))
				{
					return true;
				}
			}
			return false;
		}
Example #30
0
 public override int GetNextCaretPosition(int visualColumn, LogicalDirection direction, CaretPositioningMode mode)
 {
     // only place a caret stop before the newline, no caret stop after it
     if (visualColumn > this.VisualColumn && direction == LogicalDirection.Backward ||
         visualColumn < this.VisualColumn && direction == LogicalDirection.Forward)
     {
         return(this.VisualColumn);
     }
     else
     {
         return(-1);
     }
 }
Example #31
0
		static TextViewPosition GetPrevCaretPosition(TextView textView, TextViewPosition caretPosition, VisualLine visualLine, CaretPositioningMode mode, bool enableVirtualSpace) {
			int pos = visualLine.GetNextCaretPosition(caretPosition.VisualColumn, LogicalDirection.Backward, mode, enableVirtualSpace);
			if (pos >= 0)
				return visualLine.GetTextViewPosition(pos);
			var previousDocumentLine = visualLine.FirstDocumentLine.PreviousLine;
			if (previousDocumentLine != null) {
				var previousLine = textView.GetOrConstructVisualLine(previousDocumentLine);
				pos = previousLine.GetNextCaretPosition(previousLine.VisualLength + 1, LogicalDirection.Backward, mode, enableVirtualSpace);
				return previousLine.GetTextViewPosition(pos);
			}
			return new TextViewPosition(0, 0);
		}
Example #32
0
        /// <summary>
        /// Gets the next caret position.
        /// </summary>
        /// <param name="textSource">The text source.</param>
        /// <param name="offset">The start offset inside the text source.</param>
        /// <param name="direction">The search direction (forwards or backwards).</param>
        /// <param name="mode">The mode for caret positioning.</param>
        /// <returns>The offset of the next caret position, or -1 if there is no further caret position
        /// in the text source.</returns>
        /// <remarks>
        /// This method is NOT equivalent to the actual caret movement when using VisualLine.GetNextCaretPosition.
        /// In real caret movement, there are additional caret stops at line starts and ends. This method
        /// treats linefeeds as simple whitespace.
        /// </remarks>
        public static int GetNextCaretPosition(ITextSource textSource, int offset, LogicalDirection direction, CaretPositioningMode mode)
        {
            if (textSource == null)
            {
                throw new ArgumentNullException("textSource");
            }
            if (mode != CaretPositioningMode.Normal &&
                mode != CaretPositioningMode.WordBorder &&
                mode != CaretPositioningMode.WordStart &&
                mode != CaretPositioningMode.WordBorderOrSymbol &&
                mode != CaretPositioningMode.WordStartOrSymbol)
            {
                throw new ArgumentException("Unsupported CaretPositioningMode: " + mode, "mode");
            }
            if (direction != LogicalDirection.Backward &&
                direction != LogicalDirection.Forward)
            {
                throw new ArgumentException("Invalid LogicalDirection: " + direction, "direction");
            }
            int textLength = textSource.TextLength;

            if (textLength <= 0)
            {
                // empty document? has a normal caret position at 0, though no word borders
                if (mode == CaretPositioningMode.Normal)
                {
                    if (offset > 0 && direction == LogicalDirection.Backward)
                    {
                        return(0);
                    }
                    if (offset < 0 && direction == LogicalDirection.Forward)
                    {
                        return(0);
                    }
                }
                return(-1);
            }
            while (true)
            {
                int nextPos = (direction == LogicalDirection.Backward) ? offset - 1 : offset + 1;

                // return -1 if there is no further caret position in the text source
                // we also need this to handle offset values outside the valid range
                if (nextPos < 0 || nextPos > textLength)
                {
                    return(-1);
                }

                // stop at every caret position? we can stop immediately.
                if (mode == CaretPositioningMode.Normal)
                {
                    return(nextPos);
                }
                // not normal mode? we're looking for word borders...

                // check if we've run against the textSource borders.
                // a 'textSource' usually isn't the whole document, but a single VisualLineElement.
                if (nextPos == 0)
                {
                    // at the document start, there's only a word border
                    // if the first character is not whitespace
                    if (!char.IsWhiteSpace(textSource.GetCharAt(0)))
                    {
                        return(nextPos);
                    }
                }
                else if (nextPos == textLength)
                {
                    // at the document end, there's never a word start
                    if (mode != CaretPositioningMode.WordStart && mode != CaretPositioningMode.WordStartOrSymbol)
                    {
                        // at the document end, there's only a word border
                        // if the last character is not whitespace
                        if (!char.IsWhiteSpace(textSource.GetCharAt(textLength - 1)))
                        {
                            return(nextPos);
                        }
                    }
                }
                else
                {
                    CharacterClass charBefore = GetCharacterClass(textSource.GetCharAt(nextPos - 1));
                    CharacterClass charAfter  = GetCharacterClass(textSource.GetCharAt(nextPos));
                    if (charBefore == charAfter)
                    {
                        if (charBefore == CharacterClass.Other &&
                            (mode == CaretPositioningMode.WordBorderOrSymbol || mode == CaretPositioningMode.WordStartOrSymbol))
                        {
                            // With the "OrSymbol" modes, there's a word border and start between any two unknown characters
                            return(nextPos);
                        }
                    }
                    else
                    {
                        // this looks like a possible border

                        // if we're looking for word starts, check that this is a word start (and not a word end)
                        // if we're just checking for word borders, accept unconditionally
                        if (!((mode == CaretPositioningMode.WordStart || mode == CaretPositioningMode.WordStartOrSymbol) &&
                              (charAfter == CharacterClass.Whitespace || charAfter == CharacterClass.LineTerminator)))
                        {
                            return(nextPos);
                        }
                    }
                }
                // we'll have to continue searching...
                offset = nextPos;
            }
        }
 public override int GetNextCaretPosition(int visualColumn, LogicalDirection direction, CaretPositioningMode mode)
 {
     if (mode == CaretPositioningMode.Normal || mode == CaretPositioningMode.EveryCodepoint)
         return base.GetNextCaretPosition(visualColumn, direction, mode);
     else
         return -1;
 }
		/// <inheritdoc/>
		public override int GetNextCaretPosition(int visualColumn, LogicalDirection direction, CaretPositioningMode mode)
		{
			int textOffset = parentVisualLine.FirstDocumentLine.Offset + this.RelativeTextOffset;
			TextSourceView view = new TextSourceView(
				parentVisualLine.FirstDocumentLine.Document,
				new SimpleSegment(textOffset, this.DocumentLength));
			int pos = TextUtilities.GetNextCaretPosition(view, visualColumn - this.VisualColumn, direction, mode);
			if (pos < 0)
				return pos;
			else
				return this.VisualColumn + pos;
		}
Example #35
0
        /// <summary>
        /// Gets the next caret position.
        /// </summary>
        /// <param name="textSource">The text source.</param>
        /// <param name="offset">The start offset inside the text source.</param>
        /// <param name="direction">The search direction (forwards or backwards).</param>
        /// <param name="mode">The mode for caret positioning.</param>
        /// <returns>The offset of the next caret position, or -1 if there is no further caret position
        /// in the text source.</returns>
        /// <remarks>
        /// This method is NOT equivalent to the actual caret movement when using VisualLine.GetNextCaretPosition.
        /// In real caret movement, there are additional caret stops at line starts and ends. This method
        /// treats linefeeds as simple whitespace.
        /// </remarks>
        public static int GetNextCaretPosition(ITextSource textSource, int offset, LogicalDirection direction, CaretPositioningMode mode)
        {
            if (textSource == null)
            {
                throw new ArgumentNullException("textSource");
            }
            switch (mode)
            {
            case CaretPositioningMode.Normal:
            case CaretPositioningMode.EveryCodepoint:
            case CaretPositioningMode.WordBorder:
            case CaretPositioningMode.WordBorderOrSymbol:
            case CaretPositioningMode.WordStart:
            case CaretPositioningMode.WordStartOrSymbol:
                break;                         // OK

            default:
                throw new ArgumentException("Unsupported CaretPositioningMode: " + mode, "mode");
            }
            if (direction != LogicalDirection.Backward &&
                direction != LogicalDirection.Forward)
            {
                throw new ArgumentException("Invalid LogicalDirection: " + direction, "direction");
            }
            int textLength = textSource.TextLength;

            if (textLength <= 0)
            {
                // empty document? has a normal caret position at 0, though no word borders
                if (IsNormal(mode))
                {
                    if (offset > 0 && direction == LogicalDirection.Backward)
                    {
                        return(0);
                    }
                    if (offset < 0 && direction == LogicalDirection.Forward)
                    {
                        return(0);
                    }
                }
                return(-1);
            }
            while (true)
            {
                int nextPos = (direction == LogicalDirection.Backward) ? offset - 1 : offset + 1;

                // return -1 if there is no further caret position in the text source
                // we also need this to handle offset values outside the valid range
                if (nextPos < 0 || nextPos > textLength)
                {
                    return(-1);
                }

                // check if we've run against the textSource borders.
                // a 'textSource' usually isn't the whole document, but a single VisualLineElement.
                if (nextPos == 0)
                {
                    // at the document start, there's only a word border
                    // if the first character is not whitespace
                    if (IsNormal(mode) || !char.IsWhiteSpace(textSource.GetCharAt(0)))
                    {
                        return(nextPos);
                    }
                }
                else if (nextPos == textLength)
                {
                    // at the document end, there's never a word start
                    if (mode != CaretPositioningMode.WordStart && mode != CaretPositioningMode.WordStartOrSymbol)
                    {
                        // at the document end, there's only a word border
                        // if the last character is not whitespace
                        if (IsNormal(mode) || !char.IsWhiteSpace(textSource.GetCharAt(textLength - 1)))
                        {
                            return(nextPos);
                        }
                    }
                }
                else
                {
                    char charBefore = textSource.GetCharAt(nextPos - 1);
                    char charAfter  = textSource.GetCharAt(nextPos);
                    // Don't stop in the middle of a surrogate pair
                    if (!char.IsSurrogatePair(charBefore, charAfter))
                    {
                        CharacterClass classBefore = GetCharacterClass(charBefore);
                        CharacterClass classAfter  = GetCharacterClass(charAfter);
                        // get correct class for characters outside BMP:
                        if (char.IsLowSurrogate(charBefore) && nextPos >= 2)
                        {
                            classBefore = GetCharacterClass(textSource.GetCharAt(nextPos - 2), charBefore);
                        }
                        if (char.IsHighSurrogate(charAfter) && nextPos + 1 < textLength)
                        {
                            classAfter = GetCharacterClass(charAfter, textSource.GetCharAt(nextPos + 1));
                        }
                        if (StopBetweenCharacters(mode, classBefore, classAfter))
                        {
                            return(nextPos);
                        }
                    }
                }
                // we'll have to continue searching...
                offset = nextPos;
            }
        }
Example #36
0
 static bool IsNormal(CaretPositioningMode mode)
 {
     return(mode == CaretPositioningMode.Normal || mode == CaretPositioningMode.EveryCodepoint);
 }
Example #37
0
 static bool HasImplicitStopAtLineEnd(CaretPositioningMode mode)
 {
     return true;
 }
		static TextViewPosition GetNextCaretPosition(TextView textView, TextViewPosition caretPosition, VisualLine visualLine, CaretPositioningMode mode, bool enableVirtualSpace)
		{
			int pos = visualLine.GetNextCaretPosition(caretPosition.VisualColumn, LogicalDirection.Forward, mode, enableVirtualSpace);
			if (pos >= 0) {
				return visualLine.GetTextViewPosition(pos);
			} else {
				// move to start of next line
				DocumentLine nextDocumentLine = visualLine.LastDocumentLine.NextLine;
				if (nextDocumentLine != null) {
					VisualLine nextLine = textView.GetOrConstructVisualLine(nextDocumentLine);
					pos = nextLine.GetNextCaretPosition(-1, LogicalDirection.Forward, mode, enableVirtualSpace);
					if (pos < 0)
						throw ThrowUtil.NoValidCaretPosition();
					return nextLine.GetTextViewPosition(pos);
				} else {
					// at end of document
					Debug.Assert(visualLine.LastDocumentLine.Offset + visualLine.LastDocumentLine.TotalLength == textView.Document.TextLength);
					return new TextViewPosition(textView.Document.GetLocation(textView.Document.TextLength));
				}
			}
		}
Example #39
0
 static bool HasStopsInVirtualSpace(CaretPositioningMode mode)
 {
     return mode == CaretPositioningMode.Normal;
 }
		static TextViewPosition GetPrevCaretPosition(TextView textView, TextViewPosition caretPosition, VisualLine visualLine, CaretPositioningMode mode, bool enableVirtualSpace)
		{
			int pos = visualLine.GetNextCaretPosition(caretPosition.VisualColumn, LogicalDirection.Backward, mode, enableVirtualSpace);
			if (pos >= 0) {
				return visualLine.GetTextViewPosition(pos);
			} else {
				// move to end of previous line
				DocumentLine previousDocumentLine = visualLine.FirstDocumentLine.PreviousLine;
				if (previousDocumentLine != null) {
					VisualLine previousLine = textView.GetOrConstructVisualLine(previousDocumentLine);
					pos = previousLine.GetNextCaretPosition(previousLine.VisualLength + 1, LogicalDirection.Backward, mode, enableVirtualSpace);
					if (pos < 0)
						throw ThrowUtil.NoValidCaretPosition();
					return previousLine.GetTextViewPosition(pos);
				} else {
					// at start of document
					Debug.Assert(visualLine.FirstDocumentLine.Offset == 0);
					return new TextViewPosition(0, 0);
				}
			}
		}
 private int MoveOffset(int offset, CaretPositioningMode mode, int count)
 {
     var direction = count < 0 ? LogicalDirection.Backward : LogicalDirection.Forward;
     count = Math.Abs(count);
     for (int i = 0; i < count; i++) {
         int newOffset = TextUtilities.GetNextCaretPosition(doc, offset, direction, mode);
         if (newOffset == offset || newOffset < 0)
             break;
         offset = newOffset;
     }
     return offset;
 }
Example #42
0
		static bool HasStopsInVirtualSpace(CaretPositioningMode mode)
		{
			return mode == CaretPositioningMode.Normal || mode == CaretPositioningMode.EveryCodepoint;
		}
Example #43
0
		int GetPrevCaretStop(string text, int offset, CaretPositioningMode mode)
		{
			return TextUtilities.GetNextCaretPosition(new StringTextSource(text), offset, LogicalDirection.Backward, mode);
		}
Example #44
0
 static bool HasStopsInVirtualSpace(CaretPositioningMode mode)
 {
     return(mode == CaretPositioningMode.Normal);
 }