Code Coverage Statistics for Source File
c:\Tools\SD3\src\Libraries\ICSharpCode.TextEditor\Project\Src\Document\LineManager\LineSegment.cs
|
Sequence Point Coverage
N/A
0 of 0
|
Branch Coverage
N/A
0 of 0
|
Lines
251
|
Highlight:
Uncovered Code
Covered Code
| L | V | Source |
|---|---|---|
1 |
// <file> |
|
2 |
// <copyright see="prj:///doc/copyright.txt"/> |
|
3 |
// <license see="prj:///doc/license.txt"/> |
|
4 |
// <owner name="Mike Krüger" email="mike@icsharpcode.net"/> |
|
5 |
// <version>$Revision: 2691 $</version> |
|
6 |
// </file> |
|
7 |
||
8 |
using System; |
|
9 |
using System.Collections.Generic; |
|
10 |
using System.Drawing; |
|
11 |
using System.Diagnostics; |
|
12 |
using System.Text; |
|
13 |
||
14 |
namespace ICSharpCode.TextEditor.Document |
|
15 |
{ |
|
16 |
public sealed class LineSegment : ISegment |
|
17 |
{ |
|
18 |
internal LineSegmentTree.Enumerator treeEntry; |
|
19 |
int totalLength, delimiterLength; |
|
20 |
||
21 |
List<TextWord> words; |
|
22 |
SpanStack highlightSpanStack; |
|
23 |
||
24 |
public TextWord GetWord(int column) |
|
25 |
{ |
|
26 |
int curColumn = 0; |
|
27 |
foreach (TextWord word in words) { |
|
28 |
if (column < curColumn + word.Length) { |
|
29 |
return word; |
|
30 |
} |
|
31 |
curColumn += word.Length; |
|
32 |
} |
|
33 |
return null; |
|
34 |
} |
|
35 |
||
36 |
public bool IsDeleted { |
|
37 |
get { return !treeEntry.IsValid; } |
|
38 |
} |
|
39 |
||
40 |
public int LineNumber { |
|
41 |
get { return treeEntry.CurrentIndex; } |
|
42 |
} |
|
43 |
||
44 |
public int Offset { |
|
45 |
get { return treeEntry.CurrentOffset; } |
|
46 |
} |
|
47 |
||
48 |
public int Length { |
|
49 |
get { return totalLength - delimiterLength; } |
|
50 |
} |
|
51 |
||
52 |
int ISegment.Offset { |
|
53 |
get { return this.Offset; } |
|
54 |
set { throw new NotSupportedException(); } |
|
55 |
} |
|
56 |
int ISegment.Length { |
|
57 |
get { return this.Length; } |
|
58 |
set { throw new NotSupportedException(); } |
|
59 |
} |
|
60 |
||
61 |
public int TotalLength { |
|
62 |
get { return totalLength; } |
|
63 |
internal set { totalLength = value; } |
|
64 |
} |
|
65 |
||
66 |
public int DelimiterLength { |
|
67 |
get { return delimiterLength; } |
|
68 |
internal set { delimiterLength = value; } |
|
69 |
} |
|
70 |
||
71 |
// highlighting information |
|
72 |
public List<TextWord> Words { |
|
73 |
get { |
|
74 |
return words; |
|
75 |
} |
|
76 |
set { |
|
77 |
words = value; |
|
78 |
} |
|
79 |
} |
|
80 |
||
81 |
public HighlightColor GetColorForPosition(int x) |
|
82 |
{ |
|
83 |
if (Words != null) { |
|
84 |
int xPos = 0; |
|
85 |
foreach (TextWord word in Words) { |
|
86 |
if (x < xPos + word.Length) { |
|
87 |
return word.SyntaxColor; |
|
88 |
} |
|
89 |
xPos += word.Length; |
|
90 |
} |
|
91 |
} |
|
92 |
return new HighlightColor(Color.Black, false, false); |
|
93 |
} |
|
94 |
||
95 |
public SpanStack HighlightSpanStack { |
|
96 |
get { |
|
97 |
return highlightSpanStack; |
|
98 |
} |
|
99 |
set { |
|
100 |
highlightSpanStack = value; |
|
101 |
} |
|
102 |
} |
|
103 |
||
104 |
/// <summary> |
|
105 |
/// Converts a <see cref="LineSegment"/> instance to string (for debug purposes) |
|
106 |
/// </summary> |
|
107 |
public override string ToString() |
|
108 |
{ |
|
109 |
if (IsDeleted) |
|
110 |
return "[LineSegment: (deleted) Length = " + Length + ", TotalLength = " + TotalLength + ", DelimiterLength = " + delimiterLength + "]"; |
|
111 |
else |
|
112 |
return "[LineSegment: LineNumber=" + LineNumber + ", Offset = "+ Offset +", Length = " + Length + ", TotalLength = " + TotalLength + ", DelimiterLength = " + delimiterLength + "]"; |
|
113 |
} |
|
114 |
||
115 |
#region Anchor management |
|
116 |
Util.WeakCollection<TextAnchor> anchors; |
|
117 |
||
118 |
public TextAnchor CreateAnchor(int column) |
|
119 |
{ |
|
120 |
TextAnchor anchor = new TextAnchor(this, column); |
|
121 |
AddAnchor(anchor); |
|
122 |
return anchor; |
|
123 |
} |
|
124 |
||
125 |
void AddAnchor(TextAnchor anchor) |
|
126 |
{ |
|
127 |
Debug.Assert(anchor.Line == this); |
|
128 |
||
129 |
if (anchors == null) |
|
130 |
anchors = new Util.WeakCollection<TextAnchor>(); |
|
131 |
||
132 |
anchors.Add(anchor); |
|
133 |
} |
|
134 |
||
135 |
/// <summary> |
|
136 |
/// Is called when the LineSegment is deleted. |
|
137 |
/// </summary> |
|
138 |
internal void Deleted() |
|
139 |
{ |
|
140 |
//Console.WriteLine("Deleted"); |
|
141 |
treeEntry = LineSegmentTree.Enumerator.Invalid; |
|
142 |
if (anchors != null) { |
|
143 |
foreach (TextAnchor a in anchors) { |
|
144 |
a.Deleted(); |
|
145 |
} |
|
146 |
anchors = null; |
|
147 |
} |
|
148 |
} |
|
149 |
||
150 |
/// <summary> |
|
151 |
/// Is called when a part of the line is removed. |
|
152 |
/// </summary> |
|
153 |
internal void RemovedLinePart(int startColumn, int length) |
|
154 |
{ |
|
155 |
if (length == 0) |
|
156 |
return; |
|
157 |
Debug.Assert(length > 0); |
|
158 |
||
159 |
//Console.WriteLine("RemovedLinePart " + startColumn + ", " + length); |
|
160 |
if (anchors != null) { |
|
161 |
List<TextAnchor> deletedAnchors = null; |
|
162 |
foreach (TextAnchor a in anchors) { |
|
163 |
if (a.ColumnNumber > startColumn) { |
|
164 |
if (a.ColumnNumber >= startColumn + length) { |
|
165 |
a.ColumnNumber -= length; |
|
166 |
} else { |
|
167 |
if (deletedAnchors == null) |
|
168 |
deletedAnchors = new List<TextAnchor>(); |
|
169 |
a.Deleted(); |
|
170 |
deletedAnchors.Add(a); |
|
171 |
} |
|
172 |
} |
|
173 |
} |
|
174 |
if (deletedAnchors != null) { |
|
175 |
foreach (TextAnchor a in deletedAnchors) { |
|
176 |
anchors.Remove(a); |
|
177 |
} |
|
178 |
} |
|
179 |
} |
|
180 |
} |
|
181 |
||
182 |
/// <summary> |
|
183 |
/// Is called when a part of the line is inserted. |
|
184 |
/// </summary> |
|
185 |
internal void InsertedLinePart(int startColumn, int length) |
|
186 |
{ |
|
187 |
if (length == 0) |
|
188 |
return; |
|
189 |
Debug.Assert(length > 0); |
|
190 |
||
191 |
//Console.WriteLine("InsertedLinePart " + startColumn + ", " + length); |
|
192 |
if (anchors != null) { |
|
193 |
foreach (TextAnchor a in anchors) { |
|
194 |
if (a.ColumnNumber >= startColumn) { |
|
195 |
a.ColumnNumber += length; |
|
196 |
} |
|
197 |
} |
|
198 |
} |
|
199 |
} |
|
200 |
||
201 |
/// <summary> |
|
202 |
/// Is called after another line's content is appended to this line because the newline in between |
|
203 |
/// was deleted. |
|
204 |
/// The DefaultLineManager will call Deleted() on the deletedLine after the MergedWith call. |
|
205 |
/// |
|
206 |
/// firstLineLength: the length of the line before the merge. |
|
207 |
/// </summary> |
|
208 |
internal void MergedWith(LineSegment deletedLine, int firstLineLength) |
|
209 |
{ |
|
210 |
//Console.WriteLine("MergedWith"); |
|
211 |
||
212 |
if (deletedLine.anchors != null) { |
|
213 |
foreach (TextAnchor a in deletedLine.anchors) { |
|
214 |
a.Line = this; |
|
215 |
AddAnchor(a); |
|
216 |
a.ColumnNumber += firstLineLength; |
|
217 |
} |
|
218 |
deletedLine.anchors = null; |
|
219 |
} |
|
220 |
} |
|
221 |
||
222 |
/// <summary> |
|
223 |
/// Is called after a newline was inserted into this line, splitting it into this and followingLine. |
|
224 |
/// </summary> |
|
225 |
internal void SplitTo(LineSegment followingLine) |
|
226 |
{ |
|
227 |
//Console.WriteLine("SplitTo"); |
|
228 |
||
229 |
if (anchors != null) { |
|
230 |
List<TextAnchor> movedAnchors = null; |
|
231 |
foreach (TextAnchor a in anchors) { |
|
232 |
if (a.ColumnNumber > this.Length) { |
|
233 |
a.Line = followingLine; |
|
234 |
followingLine.AddAnchor(a); |
|
235 |
a.ColumnNumber -= this.Length; |
|
236 |
||
237 |
if (movedAnchors == null) |
|
238 |
movedAnchors = new List<TextAnchor>(); |
|
239 |
movedAnchors.Add(a); |
|
240 |
} |
|
241 |
} |
|
242 |
if (movedAnchors != null) { |
|
243 |
foreach (TextAnchor a in movedAnchors) { |
|
244 |
anchors.Remove(a); |
|
245 |
} |
|
246 |
} |
|
247 |
} |
|
248 |
} |
|
249 |
#endregion |
|
250 |
} |
|
251 |
} |