Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(39)

Side by Side Diff: lib/src/file.dart

Issue 1028813002: Introduce span with line context (Closed) Base URL: git@github.com:dart-lang/source_span.git@master
Patch Set: Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library source_span.file; 5 library source_span.file;
6 6
7 import 'dart:math' as math; 7 import 'dart:math' as math;
8 import 'dart:typed_data'; 8 import 'dart:typed_data';
9 9
10 import 'package:path/path.dart' as p; 10 import 'package:path/path.dart' as p;
(...skipping 30 matching lines...) Expand all
41 41
42 /// The length of the file in characters. 42 /// The length of the file in characters.
43 int get length => _decodedChars.length; 43 int get length => _decodedChars.length;
44 44
45 /// The number of lines in the file. 45 /// The number of lines in the file.
46 int get lines => _lineStarts.length; 46 int get lines => _lineStarts.length;
47 47
48 /// Creates a new source file from [text]. 48 /// Creates a new source file from [text].
49 /// 49 ///
50 /// [url] may be either a [String], a [Uri], or `null`. 50 /// [url] may be either a [String], a [Uri], or `null`.
51 SourceFile(String text, {url}) 51 SourceFile(String text, {url}) : this.decoded(text.runes, url: url);
52 : this.decoded(text.runes, url: url);
53 52
54 /// Creates a new source file from a list of decoded characters. 53 /// Creates a new source file from a list of decoded characters.
55 /// 54 ///
56 /// [url] may be either a [String], a [Uri], or `null`. 55 /// [url] may be either a [String], a [Uri], or `null`.
57 SourceFile.decoded(Iterable<int> decodedChars, {url}) 56 SourceFile.decoded(Iterable<int> decodedChars, {url})
58 : url = url is String ? Uri.parse(url) : url, 57 : url = url is String ? Uri.parse(url) : url,
59 _decodedChars = new Uint32List.fromList(decodedChars.toList()) { 58 _decodedChars = new Uint32List.fromList(decodedChars.toList()) {
60 for (var i = 0; i < _decodedChars.length; i++) { 59 for (var i = 0; i < _decodedChars.length; i++) {
61 var c = _decodedChars[i]; 60 var c = _decodedChars[i];
62 if (c == _CR) { 61 if (c == _CR) {
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
157 /// 156 ///
158 /// A [FileLocation] can be created using [SourceFile.location]. 157 /// A [FileLocation] can be created using [SourceFile.location].
159 class FileLocation extends SourceLocation { 158 class FileLocation extends SourceLocation {
160 /// The [file] that [this] belongs to. 159 /// The [file] that [this] belongs to.
161 final SourceFile file; 160 final SourceFile file;
162 161
163 Uri get sourceUrl => file.url; 162 Uri get sourceUrl => file.url;
164 int get line => file.getLine(offset); 163 int get line => file.getLine(offset);
165 int get column => file.getColumn(offset); 164 int get column => file.getColumn(offset);
166 165
167 FileLocation._(this.file, int offset) 166 FileLocation._(this.file, int offset) : super(offset) {
168 : super(offset) {
169 if (offset > file.length) { 167 if (offset > file.length) {
170 throw new RangeError("Offset $offset must not be greater than the number " 168 throw new RangeError("Offset $offset must not be greater than the number "
171 "of characters in the file, ${file.length}."); 169 "of characters in the file, ${file.length}.");
172 } 170 }
173 } 171 }
174 172
175 FileSpan pointSpan() => new FileSpan._(file, offset, offset); 173 FileSpan pointSpan() => new FileSpan._(file, offset, offset);
176 } 174 }
177 175
178 /// A [SourceSpan] within a [SourceFile]. 176 /// A [SourceSpan] within a [SourceFile].
179 /// 177 ///
180 /// Unlike the base [SourceSpan], [FileSpan] lazily computes its line and column 178 /// Unlike the base [SourceSpan], [FileSpan] lazily computes its line and column
181 /// values based on its offset and the contents of [file]. [FileSpan.message] is 179 /// values based on its offset and the contents of [file]. [FileSpan.message] is
182 /// also able to provide more context then [SourceSpan.message], and 180 /// also able to provide more context then [SourceSpan.message], and
183 /// [FileSpan.union] will return a [FileSpan] if possible. 181 /// [FileSpan.union] will return a [FileSpan] if possible.
184 /// 182 ///
185 /// A [FileSpan] can be created using [SourceFile.span]. 183 /// A [FileSpan] can be created using [SourceFile.span].
186 class FileSpan extends SourceSpanMixin { 184 class FileSpan extends SourceSpanMixin implements SourceSpanWithContext {
187 /// The [file] that [this] belongs to. 185 /// The [file] that [this] belongs to.
188 final SourceFile file; 186 final SourceFile file;
189 187
190 /// The offset of the beginning of the span. 188 /// The offset of the beginning of the span.
191 /// 189 ///
192 /// [start] is lazily generated from this to avoid allocating unnecessary 190 /// [start] is lazily generated from this to avoid allocating unnecessary
193 /// objects. 191 /// objects.
194 final int _start; 192 final int _start;
195 193
196 /// The offset of the end of the span. 194 /// The offset of the end of the span.
197 /// 195 ///
198 /// [end] is lazily generated from this to avoid allocating unnecessary 196 /// [end] is lazily generated from this to avoid allocating unnecessary
199 /// objects. 197 /// objects.
200 final int _end; 198 final int _end;
201 199
202 Uri get sourceUrl => file.url; 200 Uri get sourceUrl => file.url;
203 int get length => _end - _start; 201 int get length => _end - _start;
204 FileLocation get start => new FileLocation._(file, _start); 202 FileLocation get start => new FileLocation._(file, _start);
205 FileLocation get end => new FileLocation._(file, _end); 203 FileLocation get end => new FileLocation._(file, _end);
206 String get text => file.getText(_start, _end); 204 String get text => file.getText(_start, _end);
207 205
206 String get context {
207 var line = start.line;
208 return file.getText(file.getOffset(line),
209 line == file.lines - 1 ? null : file.getOffset(line + 1));
210 }
211
208 FileSpan._(this.file, this._start, this._end) { 212 FileSpan._(this.file, this._start, this._end) {
209 if (_end < _start) { 213 if (_end < _start) {
210 throw new ArgumentError('End $_end must come after start $_start.'); 214 throw new ArgumentError('End $_end must come after start $_start.');
211 } else if (_end > file.length) { 215 } else if (_end > file.length) {
212 throw new RangeError("End $_end must not be greater than the number " 216 throw new RangeError("End $_end must not be greater than the number "
213 "of characters in the file, ${file.length}."); 217 "of characters in the file, ${file.length}.");
214 } else if (_start < 0) { 218 } else if (_start < 0) {
215 throw new RangeError("Start may not be negative, was $_start."); 219 throw new RangeError("Start may not be negative, was $_start.");
216 } 220 }
217 } 221 }
(...skipping 15 matching lines...) Expand all
233 237
234 if (beginSpan._end < endSpan._start) { 238 if (beginSpan._end < endSpan._start) {
235 throw new ArgumentError("Spans $this and $other are disjoint."); 239 throw new ArgumentError("Spans $this and $other are disjoint.");
236 } 240 }
237 241
238 return span; 242 return span;
239 } 243 }
240 244
241 bool operator ==(other) { 245 bool operator ==(other) {
242 if (other is! FileSpan) return super == other; 246 if (other is! FileSpan) return super == other;
243 return _start == other._start && _end == other._end && 247 return _start == other._start &&
248 _end == other._end &&
244 sourceUrl == other.sourceUrl; 249 sourceUrl == other.sourceUrl;
245 } 250 }
246 251
247 int get hashCode => _start.hashCode + 5 * _end.hashCode + 252 int get hashCode =>
248 7 * sourceUrl.hashCode; 253 _start.hashCode + 5 * _end.hashCode + 7 * sourceUrl.hashCode;
249 254
250 /// Returns a new span that covers both [this] and [other]. 255 /// Returns a new span that covers both [this] and [other].
251 /// 256 ///
252 /// Unlike [union], [other] may be disjoint from [this]. If it is, the text 257 /// Unlike [union], [other] may be disjoint from [this]. If it is, the text
253 /// between the two will be covered by the returned span. 258 /// between the two will be covered by the returned span.
254 FileSpan expand(FileSpan other) { 259 FileSpan expand(FileSpan other) {
255 if (sourceUrl != other.sourceUrl) { 260 if (sourceUrl != other.sourceUrl) {
256 throw new ArgumentError("Source URLs \"${sourceUrl}\" and " 261 throw new ArgumentError("Source URLs \"${sourceUrl}\" and "
257 " \"${other.sourceUrl}\" don't match."); 262 " \"${other.sourceUrl}\" don't match.");
258 } 263 }
259 264
260 var start = math.min(this._start, other._start); 265 var start = math.min(this._start, other._start);
261 var end = math.max(this._end, other._end); 266 var end = math.max(this._end, other._end);
262 return new FileSpan._(file, start, end); 267 return new FileSpan._(file, start, end);
263 } 268 }
264
265 String message(String message, {color}) {
266 if (color == true) color = colors.RED;
267 if (color == false) color = null;
268
269 var line = start.line;
270 var column = start.column;
271
272 var buffer = new StringBuffer();
273 buffer.write('line ${start.line + 1}, column ${start.column + 1}');
274 if (sourceUrl != null) buffer.write(' of ${p.prettyUri(sourceUrl)}');
275 buffer.write(': $message\n');
276
277 var textLine = file.getText(file.getOffset(line),
278 line == file.lines - 1 ? null : file.getOffset(line + 1));
279
280 column = math.min(column, textLine.length - 1);
281 var toColumn =
282 math.min(column + end.offset - start.offset, textLine.length);
283
284 if (color != null) {
285 buffer.write(textLine.substring(0, column));
286 buffer.write(color);
287 buffer.write(textLine.substring(column, toColumn));
288 buffer.write(colors.NONE);
289 buffer.write(textLine.substring(toColumn));
290 } else {
291 buffer.write(textLine);
292 }
293 if (!textLine.endsWith('\n')) buffer.write('\n');
294
295 buffer.write(' ' * column);
296 if (color != null) buffer.write(color);
297 buffer.write('^' * math.max(toColumn - column, 1));
298 if (color != null) buffer.write(colors.NONE);
299 return buffer.toString();
300 }
301 } 269 }
OLDNEW
« no previous file with comments | « lib/src/colors.dart ('k') | lib/src/location.dart » ('j') | lib/src/span.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698