aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Editing/SimpleSelection.cs
blob: 132b09e201262d66a76f85a498616f2accd8333b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)

using System;
using System.Collections.Generic;
using System.Linq;

using Tango.Scripting.Editors.Document;
using Tango.Scripting.Editors.Utils;

namespace Tango.Scripting.Editors.Editing
{
	/// <summary>
	/// A simple selection.
	/// </summary>
	sealed class SimpleSelection : Selection
	{
		readonly TextViewPosition start, end;
		readonly int startOffset, endOffset;
		
		/// <summary>
		/// Creates a new SimpleSelection instance.
		/// </summary>
		internal SimpleSelection(TextArea textArea, TextViewPosition start, TextViewPosition end)
			: base(textArea)
		{
			this.start = start;
			this.end = end;
			this.startOffset = textArea.Document.GetOffset(start.Location);
			this.endOffset = textArea.Document.GetOffset(end.Location);
		}
		
		/// <inheritdoc/>
		public override IEnumerable<SelectionSegment> Segments {
			get {
				return ExtensionMethods.Sequence<SelectionSegment>(new SelectionSegment(startOffset, start.VisualColumn, endOffset, end.VisualColumn));
			}
		}
		
		/// <inheritdoc/>
		public override ISegment SurroundingSegment {
			get {
				return new SelectionSegment(startOffset, endOffset);
			}
		}
		
		/// <inheritdoc/>
		public override void ReplaceSelectionWithText(string newText)
		{
			if (newText == null)
				throw new ArgumentNullException("newText");
			using (textArea.Document.RunUpdate()) {
				ISegment[] segmentsToDelete = textArea.GetDeletableSegments(this.SurroundingSegment);
				for (int i = segmentsToDelete.Length - 1; i >= 0; i--) {
					if (i == segmentsToDelete.Length - 1) {
						if (segmentsToDelete[i].Offset == SurroundingSegment.Offset && segmentsToDelete[i].Length == SurroundingSegment.Length) {
							newText = AddSpacesIfRequired(newText, start, end);
						}
						int vc = textArea.Caret.VisualColumn;
						textArea.Caret.Offset = segmentsToDelete[i].EndOffset;
						if (string.IsNullOrEmpty(newText))
							textArea.Caret.VisualColumn = vc;
						textArea.Document.Replace(segmentsToDelete[i], newText);
					} else {
						textArea.Document.Remove(segmentsToDelete[i]);
					}
				}
				if (segmentsToDelete.Length != 0) {
					textArea.ClearSelection();
				}
			}
		}
		
		public override TextViewPosition StartPosition {
			get { return start; }
		}
		
		public override TextViewPosition EndPosition {
			get { return end; }
		}
		
		/// <inheritdoc/>
		public override Selection UpdateOnDocumentChange(DocumentChangeEventArgs e)
		{
			if (e == null)
				throw new ArgumentNullException("e");
			return Selection.Create(
				textArea,
				new TextViewPosition(textArea.Document.GetLocation(e.GetNewOffset(startOffset, AnchorMovementType.Default)), start.VisualColumn),
				new TextViewPosition(textArea.Document.GetLocation(e.GetNewOffset(endOffset, AnchorMovementType.Default)), end.VisualColumn)
			);
		}
		
		/// <inheritdoc/>
		public override bool IsEmpty {
			get { return startOffset == endOffset; }
		}
		
		/// <inheritdoc/>
		public override int Length {
			get {
				return Math.Abs(endOffset - startOffset);
			}
		}
		
		/// <inheritdoc/>
		public override Selection SetEndpoint(TextViewPosition endPosition)
		{
			return Create(textArea, start, endPosition);
		}
		
		public override Selection StartSelectionOrSetEndpoint(TextViewPosition startPosition, TextViewPosition endPosition)
		{
			var document = textArea.Document;
			if (document == null)
				throw ThrowUtil.NoDocumentAssigned();
			return Create(textArea, start, endPosition);
		}
		
		/// <inheritdoc/>
		public override int GetHashCode()
		{
			unchecked {
				return startOffset * 27811 + endOffset + textArea.GetHashCode();
			}
		}
		
		/// <inheritdoc/>
		public override bool Equals(object obj)
		{
			SimpleSelection other = obj as SimpleSelection;
			if (other == null) return false;
			return this.start.Equals(other.start) && this.end.Equals(other.end)
				&& this.startOffset == other.startOffset && this.endOffset == other.endOffset
				&& this.textArea == other.textArea;
		}
		
		/// <inheritdoc/>
		public override string ToString()
		{
			return "[SimpleSelection Start=" + start + " End=" + end + "]";
		}
	}
}
ass="w"> oldVisualColumn; secondPart.VisualColumn = oldVisualColumn + relativeSplitVisualColumn; firstPart.RelativeTextOffset = oldRelativeTextOffset; secondPart.RelativeTextOffset = oldRelativeTextOffset + relativeSplitRelativeTextOffset; firstPart.VisualLength = relativeSplitVisualColumn; secondPart.VisualLength = oldVisualLength - relativeSplitVisualColumn; firstPart.DocumentLength = relativeSplitRelativeTextOffset; secondPart.DocumentLength = oldDocumentLength - relativeSplitRelativeTextOffset; if (firstPart.TextRunProperties == null) firstPart.TextRunProperties = TextRunProperties.Clone(); if (secondPart.TextRunProperties == null) secondPart.TextRunProperties = TextRunProperties.Clone(); } /// <summary> /// Gets the visual column of a text location inside this element. /// The text offset is given relative to the visual line start. /// </summary> public virtual int GetVisualColumn(int relativeTextOffset) { if (relativeTextOffset >= this.RelativeTextOffset + DocumentLength) return VisualColumn + VisualLength; else return VisualColumn; } /// <summary> /// Gets the text offset of a visual column inside this element. /// </summary> /// <returns>A text offset relative to the visual line start.</returns> public virtual int GetRelativeOffset(int visualColumn) { if (visualColumn >= this.VisualColumn + VisualLength) return RelativeTextOffset + DocumentLength; else return RelativeTextOffset; } /// <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; } /// <summary> /// Gets whether the specified offset in this element is considered whitespace. /// </summary> public virtual bool IsWhitespace(int visualColumn) { return false; } /// <summary> /// Gets whether the <see cref="GetNextCaretPosition"/> implementation handles line borders. /// If this property returns false, the caller of GetNextCaretPosition should handle the line /// borders (i.e. place caret stops at the start and end of the line). /// This property has an effect only for VisualLineElements that are at the start or end of a /// <see cref="VisualLine"/>. /// </summary> public virtual bool HandlesLineBorders { get { return false; } } /// <summary> /// Queries the cursor over the visual line element. /// </summary> protected internal virtual void OnQueryCursor(QueryCursorEventArgs e) { } /// <summary> /// Allows the visual line element to handle a mouse event. /// </summary> protected internal virtual void OnMouseDown(MouseButtonEventArgs e) { } /// <summary> /// Allows the visual line element to handle a mouse event. /// </summary> protected internal virtual void OnMouseUp(MouseButtonEventArgs e) { } } }