| OLD | NEW |
| 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 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 66 } | 66 } |
| 67 if (c == _LF) _lineStarts.add(i + 1); | 67 if (c == _LF) _lineStarts.add(i + 1); |
| 68 } | 68 } |
| 69 } | 69 } |
| 70 | 70 |
| 71 /// Returns a span in [this] from [start] to [end] (exclusive). | 71 /// Returns a span in [this] from [start] to [end] (exclusive). |
| 72 /// | 72 /// |
| 73 /// If [end] isn't passed, it defaults to the end of the file. | 73 /// If [end] isn't passed, it defaults to the end of the file. |
| 74 FileSpan span(int start, [int end]) { | 74 FileSpan span(int start, [int end]) { |
| 75 if (end == null) end = length - 1; | 75 if (end == null) end = length - 1; |
| 76 return new FileSpan._(this, location(start), location(end)); | 76 return new FileSpan._(this, start, end); |
| 77 } | 77 } |
| 78 | 78 |
| 79 /// Returns a location in [this] at [offset]. | 79 /// Returns a location in [this] at [offset]. |
| 80 FileLocation location(int offset) => new FileLocation._(this, offset); | 80 FileLocation location(int offset) => new FileLocation._(this, offset); |
| 81 | 81 |
| 82 /// Gets the 0-based line corresponding to [offset]. | 82 /// Gets the 0-based line corresponding to [offset]. |
| 83 int getLine(int offset) { | 83 int getLine(int offset) { |
| 84 if (offset < 0) { | 84 if (offset < 0) { |
| 85 throw new RangeError("Offset may not be negative, was $offset."); | 85 throw new RangeError("Offset may not be negative, was $offset."); |
| 86 } else if (offset > length) { | 86 } else if (offset > length) { |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 165 int get column => file.getColumn(offset); | 165 int get column => file.getColumn(offset); |
| 166 | 166 |
| 167 FileLocation._(this.file, int offset) | 167 FileLocation._(this.file, int offset) |
| 168 : super(offset) { | 168 : super(offset) { |
| 169 if (offset > file.length) { | 169 if (offset > file.length) { |
| 170 throw new RangeError("Offset $offset must not be greater than the number " | 170 throw new RangeError("Offset $offset must not be greater than the number " |
| 171 "of characters in the file, ${file.length}."); | 171 "of characters in the file, ${file.length}."); |
| 172 } | 172 } |
| 173 } | 173 } |
| 174 | 174 |
| 175 FileSpan pointSpan() => new FileSpan._(file, this, this); | 175 FileSpan pointSpan() => new FileSpan._(file, offset, offset); |
| 176 } | 176 } |
| 177 | 177 |
| 178 /// A [SourceSpan] within a [SourceFile]. | 178 /// A [SourceSpan] within a [SourceFile]. |
| 179 /// | 179 /// |
| 180 /// Unlike the base [SourceSpan], [FileSpan] lazily computes its line and column | 180 /// 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 | 181 /// values based on its offset and the contents of [file]. [FileSpan.message] is |
| 182 /// also able to provide more context then [SourceSpan.message], and | 182 /// also able to provide more context then [SourceSpan.message], and |
| 183 /// [FileSpan.union] will return a [FileSpan] if possible. | 183 /// [FileSpan.union] will return a [FileSpan] if possible. |
| 184 /// | 184 /// |
| 185 /// A [FileSpan] can be created using [SourceFile.span]. | 185 /// A [FileSpan] can be created using [SourceFile.span]. |
| 186 class FileSpan extends SourceSpanMixin { | 186 class FileSpan extends SourceSpanMixin { |
| 187 /// The [file] that [this] belongs to. | 187 /// The [file] that [this] belongs to. |
| 188 final SourceFile file; | 188 final SourceFile file; |
| 189 | 189 |
| 190 final FileLocation start; | 190 /// The offset of the beginning of the span. |
| 191 final FileLocation end; | 191 /// |
| 192 /// [start] is lazily generated from this to avoid allocating unnecessary |
| 193 /// objects. |
| 194 final int _start; |
| 195 |
| 196 /// The offset of the end of the span. |
| 197 /// |
| 198 /// [end] is lazily generated from this to avoid allocating unnecessary |
| 199 /// objects. |
| 200 final int _end; |
| 201 |
| 202 FileLocation get start => new FileLocation._(file, _start); |
| 203 FileLocation get end => new FileLocation._(file, _end); |
| 192 | 204 |
| 193 String get text => file.getText(start.offset, end.offset); | 205 String get text => file.getText(start.offset, end.offset); |
| 194 | 206 |
| 195 FileSpan._(this.file, this.start, this.end) { | 207 FileSpan._(this.file, this._start, this._end) { |
| 196 if (end.offset < start.offset) { | 208 if (_end < _start) { |
| 197 throw new ArgumentError('End $end must come after start $start.'); | 209 throw new ArgumentError('End $_end must come after start $_start.'); |
| 198 } | 210 } |
| 199 } | 211 } |
| 200 | 212 |
| 201 SourceSpan union(SourceSpan other) { | 213 SourceSpan union(SourceSpan other) { |
| 202 if (other is! FileSpan) return super.union(other); | 214 if (other is! FileSpan) return super.union(other); |
| 203 | 215 |
| 204 var span = expand(other); | 216 var span = expand(other); |
| 205 var beginSpan = span.start == this.start ? this : other; | 217 var beginSpan = span.start == this.start ? this : other; |
| 206 var endSpan = span.end == this.end ? this : other; | 218 var endSpan = span.end == this.end ? this : other; |
| 207 | 219 |
| 208 if (beginSpan.end.compareTo(endSpan.start) < 0) { | 220 if (beginSpan.end.compareTo(endSpan.start) < 0) { |
| 209 throw new ArgumentError("Spans $this and $other are disjoint."); | 221 throw new ArgumentError("Spans $this and $other are disjoint."); |
| 210 } | 222 } |
| 211 | 223 |
| 212 return span; | 224 return span; |
| 213 } | 225 } |
| 214 | 226 |
| 215 /// Returns a new span that covers both [this] and [other]. | 227 /// Returns a new span that covers both [this] and [other]. |
| 216 /// | 228 /// |
| 217 /// Unlike [union], [other] may be disjoint from [this]. If it is, the text | 229 /// Unlike [union], [other] may be disjoint from [this]. If it is, the text |
| 218 /// between the two will be covered by the returned span. | 230 /// between the two will be covered by the returned span. |
| 219 FileSpan expand(FileSpan other) { | 231 FileSpan expand(FileSpan other) { |
| 220 if (sourceUrl != other.sourceUrl) { | 232 if (sourceUrl != other.sourceUrl) { |
| 221 throw new ArgumentError("Source URLs \"${sourceUrl}\" and " | 233 throw new ArgumentError("Source URLs \"${sourceUrl}\" and " |
| 222 " \"${other.sourceUrl}\" don't match."); | 234 " \"${other.sourceUrl}\" don't match."); |
| 223 } | 235 } |
| 224 | 236 |
| 225 var start = min(this.start, other.start); | 237 var start = math.min(this._start, other._start); |
| 226 var end = max(this.end, other.end); | 238 var end = math.max(this._end, other._end); |
| 227 return new FileSpan._(file, start, end); | 239 return new FileSpan._(file, start, end); |
| 228 } | 240 } |
| 229 | 241 |
| 230 String message(String message, {color}) { | 242 String message(String message, {color}) { |
| 231 if (color == true) color = colors.RED; | 243 if (color == true) color = colors.RED; |
| 232 if (color == false) color = null; | 244 if (color == false) color = null; |
| 233 | 245 |
| 234 var line = start.line; | 246 var line = start.line; |
| 235 var column = start.column; | 247 var column = start.column; |
| 236 | 248 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 257 } | 269 } |
| 258 if (!textLine.endsWith('\n')) buffer.write('\n'); | 270 if (!textLine.endsWith('\n')) buffer.write('\n'); |
| 259 | 271 |
| 260 buffer.write(' ' * column); | 272 buffer.write(' ' * column); |
| 261 if (color != null) buffer.write(color); | 273 if (color != null) buffer.write(color); |
| 262 buffer.write('^' * math.max(toColumn - column, 1)); | 274 buffer.write('^' * math.max(toColumn - column, 1)); |
| 263 if (color != null) buffer.write(colors.NONE); | 275 if (color != null) buffer.write(colors.NONE); |
| 264 return buffer.toString(); | 276 return buffer.toString(); |
| 265 } | 277 } |
| 266 } | 278 } |
| OLD | NEW |