/src/NUnit/UiException/CSharpParser/CSTokenCollection.cs
C# | 219 lines | 125 code | 35 blank | 59 comment | 6 complexity | f02aa335d837bec9d9d430c7e5ec6228 MD5 | raw file
1// **************************************************************** 2// This is free software licensed under the NUnit license. You may 3// obtain a copy of the license at http://nunit.org 4// **************************************************************** 5 6using System; 7using System.Collections.Generic; 8using System.Text; 9using System.Collections; 10 11namespace NUnit.UiException.CodeFormatters 12{ 13 /// <summary> 14 /// (formerly named CSTokenCollection) 15 /// 16 /// Manages an ordered collection of ClassifiedToken present in one line of text. 17 /// </summary> 18 public class ClassifiedTokenCollection 19 { 20 /// <summary> 21 /// Target location when building a ClassifiedToken instance on the fly. 22 /// </summary> 23 protected ClassifiedToken _token; 24 25 /// <summary> 26 /// Keeps tracks of the data source. 27 /// </summary> 28 protected FormattedCode.CodeInfo _info; 29 30 /// <summary> 31 /// Store the current line startingPosition. 32 /// </summary> 33 protected int _lineIndex; 34 35 /// <summary> 36 /// This class requires subclassing. 37 /// </summary> 38 protected ClassifiedTokenCollection() 39 { 40 _token = new InternalToken(); 41 } 42 43 /// <summary> 44 /// Gets the number of ClassifiedToken present in this line of text. 45 /// </summary> 46 public int Count 47 { 48 get 49 { 50 int count; 51 52 if (_lineIndex + 1 < _info.LineArray.Count) 53 { 54 count = _info.LineArray[_lineIndex + 1] - 55 _info.LineArray[_lineIndex]; 56 } 57 else 58 { 59 count = _info.IndexArray.Count - 60 _info.LineArray[_lineIndex]; 61 } 62 63 return (count); 64 } 65 } 66 67 /// <summary> 68 /// Gets the ClassifiedToken instance at the specified startingPosition. 69 /// Warning: this indexer always return the same instance. 70 /// To keep data safe, it is strongly recommanded to make 71 /// a deep copy of the returned ClassifiedToken. 72 /// </summary> 73 /// <param name="startingPosition">A zero based value in the range: [0 - Count[</param> 74 /// <returns>The ClassifiedToken at this startingPosition.</returns> 75 public ClassifiedToken this[int index] 76 { 77 get 78 { 79 InternalToken result; 80 81 result = (InternalToken)_token; 82 _populateToken(_lineIndex, index, result); 83 84 return (result); 85 } 86 } 87 88 /// <summary> 89 /// Gets the part of the text at the given position. 90 /// The returned string can be composed of one or severals words 91 /// all with the same style. 92 /// </summary> 93 private void _populateToken(int lineIndex, int tokenIndex, InternalToken output) 94 { 95 int tagZero; 96 int tagStart; 97 int tagEnd; 98 int strIndex_start; 99 int strIndex_end; 100 string res; 101 ClassificationTag tag; 102 103 // 104 // Gets value of tagStart and tagEnd 105 // from which string indexes can be extracted 106 // 107 108 tagZero = _info.LineArray[lineIndex]; 109 tagStart = tagZero + tokenIndex; 110 tagEnd = tagStart + 1; 111 112 strIndex_start = _info.IndexArray[tagStart]; 113 114 if (tagEnd < _info.IndexArray.Count) 115 { 116 strIndex_end = _info.IndexArray[tagEnd]; 117 res = _info.Text.Substring(strIndex_start, strIndex_end - strIndex_start); 118 } 119 else 120 res = _info.Text.Substring(strIndex_start); 121 122 // 123 // Check the need to trimEnd() the resulting string. 124 // We only want to trimEnd when current string is the 125 // last part of the current line. Intermediary strings 126 // must not be trimed end. At display time this would 127 // lead to introduce bad shifting of text sequences. 128 // 129 130 if (res.EndsWith("\n")) 131 res = res.TrimEnd(); 132 133 // 134 // Convert the byte code into a ClassificationTag 135 // for this string sequence 136 // 137 138 tag = _getTagFromByteValue(_info.TagArray[tagStart]); 139 140 // and populate result 141 142 output.Setup(res, tag); 143 144 return; 145 } 146 147 /// <summary> 148 /// Converts the given value into the matching ClassificationTag. 149 /// </summary> 150 private ClassificationTag _getTagFromByteValue(byte value) 151 { 152 switch (value) 153 { 154 case 0: return (ClassificationTag.Code); 155 case 1: return (ClassificationTag.Keyword); 156 case 2: return (ClassificationTag.Comment); 157 case 3: return (ClassificationTag.String); 158 default: 159 UiExceptionHelper.CheckTrue(false, "should not reach this code", "value"); 160 break; 161 } 162 163 return (ClassificationTag.Code); 164 } 165 166 /// <summary> 167 /// Return a string filled with the text present at the current line startingPosition. 168 /// </summary> 169 public string Text 170 { 171 get 172 { 173 int index_start; 174 int index_start_ptr; 175 int index_end; 176 int index_end_ptr; 177 string text; 178 179 index_start_ptr = _info.LineArray[_lineIndex]; 180 index_start = _info.IndexArray[index_start_ptr]; 181 182 if (_lineIndex + 1 >= _info.LineArray.Count) 183 index_end = _info.Text.Length; 184 else 185 { 186 index_end_ptr = _info.LineArray[_lineIndex + 1]; 187 index_end = _info.IndexArray[index_end_ptr]; 188 } 189 190 if (index_end - index_start < 0) 191 throw new Exception( 192 "ClassifiedTokenCollection: Text: error: calling substring with negative length"); 193 194 text = _info.Text.Substring(index_start, index_end - index_start); 195 text = text.TrimEnd(); 196 197 return (text); 198 } 199 } 200 201 #region InternalToken 202 203 class InternalToken : 204 ClassifiedToken 205 { 206 public InternalToken() 207 { 208 } 209 210 public void Setup(string text, ClassificationTag tag) 211 { 212 _text = text; 213 _tag = tag; 214 } 215 } 216 217 #endregion 218 } 219}