Code Coverage Statistics for Source File

c:\Tools\SD3\src\Libraries\ICSharpCode.TextEditor\Project\Src\Document\TextUtilities.cs

Sequence Point Coverage
N/A
0 of 0
Branch Coverage
N/A
0 of 0
Lines
313
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: 2533 $</version>
6
// </file>
7
8
using System;
9
using System.Diagnostics;
10
using System.Text;
11
12
namespace ICSharpCode.TextEditor.Document
13
{
14
	
15
	public sealed class TextUtilities
16
	{
17
		/// <remarks>
18
		/// This function takes a string and converts the whitespace in front of
19
		/// it to tabs. If the length of the whitespace at the start of the string
20
		/// was not a whole number of tabs then there will still be some spaces just
21
		/// before the text starts.
22
		/// the output string will be of the form:
23
		/// 1. zero or more tabs
24
		/// 2. zero or more spaces (less than tabIndent)
25
		/// 3. the rest of the line
26
		/// </remarks>
27
		public static string LeadingWhiteSpaceToTabs(string line, int tabIndent) {
28
			StringBuilder sb = new StringBuilder(line.Length);
29
			int consecutiveSpaces = 0;
30
			int i = 0;
31
			for(i = 0; i < line.Length; i++) {
32
				if(line[i] == ' ') {
33
					consecutiveSpaces++;
34
					if(consecutiveSpaces == tabIndent) {
35
						sb.Append('\t');
36
						consecutiveSpaces = 0;
37
					}
38
				}
39
				else if(line[i] == '\t') {
40
					sb.Append('\t');
41
					// if we had say 3 spaces then a tab and tabIndent was 4 then
42
					// we would want to simply replace all of that with 1 tab
43
					consecutiveSpaces = 0;
44
				}
45
				else {
46
					break;
47
				}
48
			}
49
			
50
			if(i < line.Length) {
51
				sb.Append(line.Substring(i-consecutiveSpaces));
52
			}
53
			return sb.ToString();
54
		}
55
		
56
		public static bool IsLetterDigitOrUnderscore(char c)
57
		{
58
			if(!Char.IsLetterOrDigit(c)) {
59
				return c == '_';
60
			}
61
			return true;
62
		}
63
		
64
		public enum CharacterType {
65
			LetterDigitOrUnderscore,
66
			WhiteSpace,
67
			Other
68
		}
69
		
70
		/// <remarks>
71
		/// This method returns the expression before a specified offset.
72
		/// That method is used in code completion to determine the expression given
73
		/// to the parser for type resolve.
74
		/// </remarks>
75
		public static string GetExpressionBeforeOffset(TextArea textArea, int initialOffset)
76
		{
77
			IDocument document = textArea.Document;
78
			int offset = initialOffset;
79
			while (offset - 1 > 0) {
80
				switch (document.GetCharAt(offset - 1)) {
81
					case '\n':
82
					case '\r':
83
					case '}':
84
						goto done;
85
//						offset = SearchBracketBackward(document, offset - 2, '{','}');
86
//						break;
87
					case ']':
88
						offset = SearchBracketBackward(document, offset - 2, '[',']');
89
						break;
90
					case ')':
91
						offset = SearchBracketBackward(document, offset - 2, '(',')');
92
						break;
93
					case '.':
94
						--offset;
95
						break;
96
					case '"':
97
						if (offset < initialOffset - 1) {
98
							return null;
99
						}
100
						return "\"\"";
101
					case '\'':
102
						if (offset < initialOffset - 1) {
103
							return null;
104
						}
105
						return "'a'";
106
					case '>':
107
						if (document.GetCharAt(offset - 2) == '-') {
108
							offset -= 2;
109
							break;
110
						}
111
						goto done;
112
					default:
113
						if (Char.IsWhiteSpace(document.GetCharAt(offset - 1))) {
114
							--offset;
115
							break;
116
						}
117
						int start = offset - 1;
118
						if (!IsLetterDigitOrUnderscore(document.GetCharAt(start))) {
119
							goto done;
120
						}
121
						
122
						while (start > 0 && IsLetterDigitOrUnderscore(document.GetCharAt(start - 1))) {
123
							--start;
124
						}
125
						string word = document.GetText(start, offset - start).Trim();
126
						switch (word) {
127
							case "ref":
128
							case "out":
129
							case "in":
130
							case "return":
131
							case "throw":
132
							case "case":
133
								goto done;
134
						}
135
						
136
						if (word.Length > 0 && !IsLetterDigitOrUnderscore(word[0])) {
137
							goto done;
138
						}
139
						offset = start;
140
						break;
141
				}
142
			}
143
		done:
144
			//// simple exit fails when : is inside comment line or any other character
145
			//// we have to check if we got several ids in resulting line, which usually happens when
146
			//// id. is typed on next line after comment one
147
			//// Would be better if lexer would parse properly such expressions. However this will cause
148
			//// modifications in this area too - to get full comment line and remove it afterwards
149
			if (offset < 0)
150
				return string.Empty;
151
			
152
			string resText=document.GetText(offset, textArea.Caret.Offset - offset ).Trim();
153
			int pos=resText.LastIndexOf('\n');
154
			if (pos>=0) {
155
				offset+=pos+1;
156
				//// whitespaces and tabs, which might be inside, will be skipped by trim below
157
			}
158
			string expression = document.GetText(offset, textArea.Caret.Offset - offset ).Trim();
159
			return expression;
160
		}
161
		
162
		
163
		public static CharacterType GetCharacterType(char c)
164
		{
165
			if(IsLetterDigitOrUnderscore(c))
166
				return CharacterType.LetterDigitOrUnderscore;
167
			if(Char.IsWhiteSpace(c))
168
				return CharacterType.WhiteSpace;
169
			return CharacterType.Other;
170
		}
171
		
172
		public static int GetFirstNonWSChar(IDocument document, int offset)
173
		{
174
			while (offset < document.TextLength && Char.IsWhiteSpace(document.GetCharAt(offset))) {
175
				++offset;
176
			}
177
			return offset;
178
		}
179
		
180
		public static int FindWordEnd(IDocument document, int offset)
181
		{
182
			LineSegment line   = document.GetLineSegmentForOffset(offset);
183
			int     endPos = line.Offset + line.Length;
184
			while (offset < endPos && IsLetterDigitOrUnderscore(document.GetCharAt(offset))) {
185
				++offset;
186
			}
187
			
188
			return offset;
189
		}
190
		
191
		public static int FindWordStart(IDocument document, int offset)
192
		{
193
			LineSegment line = document.GetLineSegmentForOffset(offset);
194
			
195
			while (offset > line.Offset && !IsLetterDigitOrUnderscore(document.GetCharAt(offset - 1))) {
196
				--offset;
197
			}
198
			
199
			return offset;
200
		}
201
		
202
		// go forward to the start of the next word
203
		// if the cursor is at the start or in the middle of a word we move to the end of the word
204
		// and then past any whitespace that follows it
205
		// if the cursor is at the start or in the middle of some whitespace we move to the start of the
206
		// next word
207
		public static int FindNextWordStart(IDocument document, int offset)
208
		{
209
			int originalOffset = offset;
210
			LineSegment line   = document.GetLineSegmentForOffset(offset);
211
			int     endPos = line.Offset + line.Length;
212
			// lets go to the end of the word, whitespace or operator
213
			CharacterType t = GetCharacterType(document.GetCharAt(offset));
214
			while (offset < endPos && GetCharacterType(document.GetCharAt(offset)) == t) {
215
				++offset;
216
			}
217
			
218
			// now we're at the end of the word, lets find the start of the next one by skipping whitespace
219
			while (offset < endPos && GetCharacterType(document.GetCharAt(offset)) == CharacterType.WhiteSpace) {
220
				++offset;
221
			}
222
223
			return offset;
224
		}
225
		
226
		// go back to the start of the word we are on
227
		// if we are already at the start of a word or if we are in whitespace, then go back
228
		// to the start of the previous word
229
		public static int FindPrevWordStart(IDocument document, int offset)
230
		{
231
			int originalOffset = offset;
232
			if (offset > 0) {
233
				LineSegment line = document.GetLineSegmentForOffset(offset);
234
				CharacterType t = GetCharacterType(document.GetCharAt(offset - 1));
235
				while (offset > line.Offset && GetCharacterType(document.GetCharAt(offset - 1)) == t) {
236
					--offset;
237
				}
238
				
239
				// if we were in whitespace, and now we're at the end of a word or operator, go back to the beginning of it
240
				if(t == CharacterType.WhiteSpace && offset > line.Offset) {
241
					t = GetCharacterType(document.GetCharAt(offset - 1));
242
					while (offset > line.Offset && GetCharacterType(document.GetCharAt(offset - 1)) == t) {
243
						--offset;
244
					}
245
				}
246
			}
247
			
248
			return offset;
249
		}
250
		
251
		public static string GetLineAsString(IDocument document, int lineNumber)
252
		{
253
			LineSegment line = document.GetLineSegment(lineNumber);
254
			return document.GetText(line.Offset, line.Length);
255
		}
256
		
257
		public static int SearchBracketBackward(IDocument document, int offset, char openBracket, char closingBracket)
258
		{
259
			return document.FormattingStrategy.SearchBracketBackward(document, offset, openBracket, closingBracket);
260
		}
261
		
262
		public static int SearchBracketForward(IDocument document, int offset, char openBracket, char closingBracket)
263
		{
264
			return document.FormattingStrategy.SearchBracketForward(document, offset, openBracket, closingBracket);
265
		}
266
		
267
		/// <remarks>
268
		/// Returns true, if the line lineNumber is empty or filled with whitespaces.
269
		/// </remarks>
270
		public static bool IsEmptyLine(IDocument document, int lineNumber)
271
		{
272
			return IsEmptyLine(document, document.GetLineSegment(lineNumber));
273
		}
274
275
		/// <remarks>
276
		/// Returns true, if the line lineNumber is empty or filled with whitespaces.
277
		/// </remarks>
278
		public static bool IsEmptyLine(IDocument document, LineSegment line)
279
		{
280
			for (int i = line.Offset; i < line.Offset + line.Length; ++i) {
281
				char ch = document.GetCharAt(i);
282
				if (!Char.IsWhiteSpace(ch)) {
283
					return false;
284
				}
285
			}
286
			return true;
287
		}
288
		
289
		static bool IsWordPart(char ch)
290
		{
291
			return IsLetterDigitOrUnderscore(ch) || ch == '.';
292
		}
293
		
294
		public static string GetWordAt(IDocument document, int offset)
295
		{
296
			if (offset < 0 || offset >= document.TextLength - 1 || !IsWordPart(document.GetCharAt(offset))) {
297
				return String.Empty;
298
			}
299
			int startOffset = offset;
300
			int endOffset   = offset;
301
			while (startOffset > 0 && IsWordPart(document.GetCharAt(startOffset - 1))) {
302
				--startOffset;
303
			}
304
			
305
			while (endOffset < document.TextLength - 1 && IsWordPart(document.GetCharAt(endOffset + 1))) {
306
				++endOffset;
307
			}
308
			
309
			Debug.Assert(endOffset >= startOffset);
310
			return document.GetText(startOffset, endOffset - startOffset + 1);
311
		}
312
	}
313
}