LCOV - code coverage report
Current view: top level - source_span-1.8.1/lib/src - span.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 0 45 0.0 %
Date: 2021-11-28 14:37:50 Functions: 0 0 -

          Line data    Source code
       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
       3             : // BSD-style license that can be found in the LICENSE file.
       4             : 
       5             : import 'package:path/path.dart' as p;
       6             : import 'package:term_glyph/term_glyph.dart' as glyph;
       7             : 
       8             : import 'charcode.dart';
       9             : import 'file.dart';
      10             : import 'highlighter.dart';
      11             : import 'location.dart';
      12             : import 'span_mixin.dart';
      13             : import 'span_with_context.dart';
      14             : 
      15             : /// A class that describes a segment of source text.
      16             : abstract class SourceSpan implements Comparable<SourceSpan> {
      17             :   /// The start location of this span.
      18             :   SourceLocation get start;
      19             : 
      20             :   /// The end location of this span, exclusive.
      21             :   SourceLocation get end;
      22             : 
      23             :   /// The source text for this span.
      24             :   String get text;
      25             : 
      26             :   /// The URL of the source (typically a file) of this span.
      27             :   ///
      28             :   /// This may be null, indicating that the source URL is unknown or
      29             :   /// unavailable.
      30             :   Uri? get sourceUrl;
      31             : 
      32             :   /// The length of this span, in characters.
      33             :   int get length;
      34             : 
      35             :   /// Creates a new span from [start] to [end] (exclusive) containing [text].
      36             :   ///
      37             :   /// [start] and [end] must have the same source URL and [start] must come
      38             :   /// before [end]. [text] must have a number of characters equal to the
      39             :   /// distance between [start] and [end].
      40           0 :   factory SourceSpan(SourceLocation start, SourceLocation end, String text) =>
      41           0 :       SourceSpanBase(start, end, text);
      42             : 
      43             :   /// Creates a new span that's the union of `this` and [other].
      44             :   ///
      45             :   /// The two spans must have the same source URL and may not be disjoint.
      46             :   /// [text] is computed by combining `this.text` and `other.text`.
      47             :   SourceSpan union(SourceSpan other);
      48             : 
      49             :   /// Compares two spans.
      50             :   ///
      51             :   /// [other] must have the same source URL as `this`. This orders spans by
      52             :   /// [start] then [length].
      53             :   @override
      54             :   int compareTo(SourceSpan other);
      55             : 
      56             :   /// Formats [message] in a human-friendly way associated with this span.
      57             :   ///
      58             :   /// [color] may either be a [String], a [bool], or `null`. If it's a string,
      59             :   /// it indicates an [ANSI terminal color escape][] that should
      60             :   /// be used to highlight the span's text (for example, `"\u001b[31m"` will
      61             :   /// color red). If it's `true`, it indicates that the text should be
      62             :   /// highlighted using the default color. If it's `false` or `null`, it
      63             :   /// indicates that the text shouldn't be highlighted.
      64             :   ///
      65             :   /// This uses the full range of Unicode characters to highlight the source
      66             :   /// span if [glyph.ascii] is `false` (the default), but only uses ASCII
      67             :   /// characters if it's `true`.
      68             :   ///
      69             :   /// [ANSI terminal color escape]: https://en.wikipedia.org/wiki/ANSI_escape_code#Colors
      70             :   String message(String message, {color});
      71             : 
      72             :   /// Prints the text associated with this span in a user-friendly way.
      73             :   ///
      74             :   /// This is identical to [message], except that it doesn't print the file
      75             :   /// name, line number, column number, or message. If [length] is 0 and this
      76             :   /// isn't a [SourceSpanWithContext], returns an empty string.
      77             :   ///
      78             :   /// [color] may either be a [String], a [bool], or `null`. If it's a string,
      79             :   /// it indicates an [ANSI terminal color escape][] that should
      80             :   /// be used to highlight the span's text (for example, `"\u001b[31m"` will
      81             :   /// color red). If it's `true`, it indicates that the text should be
      82             :   /// highlighted using the default color. If it's `false` or `null`, it
      83             :   /// indicates that the text shouldn't be highlighted.
      84             :   ///
      85             :   /// This uses the full range of Unicode characters to highlight the source
      86             :   /// span if [glyph.ascii] is `false` (the default), but only uses ASCII
      87             :   /// characters if it's `true`.
      88             :   ///
      89             :   /// [ANSI terminal color escape]: https://en.wikipedia.org/wiki/ANSI_escape_code#Colors
      90             :   String highlight({color});
      91             : }
      92             : 
      93             : /// A base class for source spans with [start], [end], and [text] known at
      94             : /// construction time.
      95             : class SourceSpanBase extends SourceSpanMixin {
      96             :   @override
      97             :   final SourceLocation start;
      98             :   @override
      99             :   final SourceLocation end;
     100             :   @override
     101             :   final String text;
     102             : 
     103           0 :   SourceSpanBase(this.start, this.end, this.text) {
     104           0 :     if (end.sourceUrl != start.sourceUrl) {
     105           0 :       throw ArgumentError('Source URLs \"${start.sourceUrl}\" and '
     106           0 :           " \"${end.sourceUrl}\" don't match.");
     107           0 :     } else if (end.offset < start.offset) {
     108           0 :       throw ArgumentError('End $end must come after start $start.');
     109           0 :     } else if (text.length != start.distance(end)) {
     110           0 :       throw ArgumentError('Text "$text" must be ${start.distance(end)} '
     111             :           'characters long.');
     112             :     }
     113             :   }
     114             : }
     115             : 
     116             : // TODO(#52): Move these to instance methods in the next breaking release.
     117             : /// Extension methods on the base [SourceSpan] API.
     118             : extension SourceSpanExtension on SourceSpan {
     119             :   /// Like [SourceSpan.message], but also highlights [secondarySpans] to provide
     120             :   /// the user with additional context.
     121             :   ///
     122             :   /// Each span takes a label ([label] for this span, and the values of the
     123             :   /// [secondarySpans] map for the secondary spans) that's used to indicate to
     124             :   /// the user what that particular span represents.
     125             :   ///
     126             :   /// If [color] is `true`, [ANSI terminal color escapes][] are used to color
     127             :   /// the resulting string. By default this span is colored red and the
     128             :   /// secondary spans are colored blue, but that can be customized by passing
     129             :   /// ANSI escape strings to [primaryColor] or [secondaryColor].
     130             :   ///
     131             :   /// [ANSI terminal color escapes]: https://en.wikipedia.org/wiki/ANSI_escape_code#Colors
     132             :   ///
     133             :   /// Each span in [secondarySpans] must refer to the same document as this
     134             :   /// span. Throws an [ArgumentError] if any secondary span has a different
     135             :   /// source URL than this span.
     136             :   ///
     137             :   /// Note that while this will work with plain [SourceSpan]s, it will produce
     138             :   /// much more useful output with [SourceSpanWithContext]s (including
     139             :   /// [FileSpan]s).
     140           0 :   String messageMultiple(
     141             :       String message, String label, Map<SourceSpan, String> secondarySpans,
     142             :       {bool color = false, String? primaryColor, String? secondaryColor}) {
     143           0 :     final buffer = StringBuffer()
     144           0 :       ..write('line ${start.line + 1}, column ${start.column + 1}');
     145           0 :     if (sourceUrl != null) buffer.write(' of ${p.prettyUri(sourceUrl)}');
     146             :     buffer
     147           0 :       ..writeln(': $message')
     148           0 :       ..write(highlightMultiple(label, secondarySpans,
     149             :           color: color,
     150             :           primaryColor: primaryColor,
     151             :           secondaryColor: secondaryColor));
     152           0 :     return buffer.toString();
     153             :   }
     154             : 
     155             :   /// Like [SourceSpan.highlight], but also highlights [secondarySpans] to
     156             :   /// provide the user with additional context.
     157             :   ///
     158             :   /// Each span takes a label ([label] for this span, and the values of the
     159             :   /// [secondarySpans] map for the secondary spans) that's used to indicate to
     160             :   /// the user what that particular span represents.
     161             :   ///
     162             :   /// If [color] is `true`, [ANSI terminal color escapes][] are used to color
     163             :   /// the resulting string. By default this span is colored red and the
     164             :   /// secondary spans are colored blue, but that can be customized by passing
     165             :   /// ANSI escape strings to [primaryColor] or [secondaryColor].
     166             :   ///
     167             :   /// [ANSI terminal color escapes]: https://en.wikipedia.org/wiki/ANSI_escape_code#Colors
     168             :   ///
     169             :   /// Each span in [secondarySpans] must refer to the same document as this
     170             :   /// span. Throws an [ArgumentError] if any secondary span has a different
     171             :   /// source URL than this span.
     172             :   ///
     173             :   /// Note that while this will work with plain [SourceSpan]s, it will produce
     174             :   /// much more useful output with [SourceSpanWithContext]s (including
     175             :   /// [FileSpan]s).
     176           0 :   String highlightMultiple(String label, Map<SourceSpan, String> secondarySpans,
     177             :           {bool color = false, String? primaryColor, String? secondaryColor}) =>
     178           0 :       Highlighter.multiple(this, label, secondarySpans,
     179             :               color: color,
     180             :               primaryColor: primaryColor,
     181             :               secondaryColor: secondaryColor)
     182           0 :           .highlight();
     183             : 
     184             :   /// Returns a span from [start] code units (inclusive) to [end] code units
     185             :   /// (exclusive) after the beginning of this span.
     186           0 :   SourceSpan subspan(int start, [int? end]) {
     187           0 :     RangeError.checkValidRange(start, end, length);
     188           0 :     if (start == 0 && (end == null || end == length)) return this;
     189             : 
     190           0 :     final text = this.text;
     191           0 :     final startLocation = this.start;
     192           0 :     var line = startLocation.line;
     193           0 :     var column = startLocation.column;
     194             : 
     195             :     // Adjust [line] and [column] as necessary if the character at [i] in [text]
     196             :     // is a newline.
     197           0 :     void consumeCodePoint(int i) {
     198           0 :       final codeUnit = text.codeUnitAt(i);
     199           0 :       if (codeUnit == $lf ||
     200             :           // A carriage return counts as a newline, but only if it's not
     201             :           // followed by a line feed.
     202           0 :           (codeUnit == $cr &&
     203           0 :               (i + 1 == text.length || text.codeUnitAt(i + 1) != $lf))) {
     204           0 :         line += 1;
     205             :         column = 0;
     206             :       } else {
     207           0 :         column += 1;
     208             :       }
     209             :     }
     210             : 
     211           0 :     for (var i = 0; i < start; i++) {
     212             :       consumeCodePoint(i);
     213             :     }
     214             : 
     215           0 :     final newStartLocation = SourceLocation(startLocation.offset + start,
     216           0 :         sourceUrl: sourceUrl, line: line, column: column);
     217             : 
     218             :     SourceLocation newEndLocation;
     219           0 :     if (end == null || end == length) {
     220           0 :       newEndLocation = this.end;
     221           0 :     } else if (end == start) {
     222             :       newEndLocation = newStartLocation;
     223             :     } else {
     224           0 :       for (var i = start; i < end; i++) {
     225             :         consumeCodePoint(i);
     226             :       }
     227           0 :       newEndLocation = SourceLocation(startLocation.offset + end,
     228           0 :           sourceUrl: sourceUrl, line: line, column: column);
     229             :     }
     230             : 
     231           0 :     return SourceSpan(
     232           0 :         newStartLocation, newEndLocation, text.substring(start, end));
     233             :   }
     234             : }

Generated by: LCOV version 1.14