Skip to content
This repository was archived by the owner on Jan 14, 2025. It is now read-only.

Add SourceSpan.highlight(). #10

Merged
merged 1 commit into from
Nov 8, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# 1.3.0

* Add `SourceSpan.highlight()`, which returns just the highlighted text that
would be included in `SourceSpan.message()`.

# 1.2.4

* Fix a new strong mode error.
Expand Down
13 changes: 13 additions & 0 deletions lib/src/span.dart
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,19 @@ abstract class SourceSpan implements Comparable<SourceSpan> {
/// should be highlighted using the default color. If it's `false` or `null`,
/// it indicates that the text shouldn't be highlighted.
String message(String message, {color});

/// Prints the text associated with this span in a user-friendly way.
///
/// This is identical to [message], except that it doesn't print the file
/// name, line number, column number, or message. If [length] is 0 and this
/// isn't a [SourceSpanWithContext], returns an empty string.
///
/// [color] may either be a [String], a [bool], or `null`. If it's a string,
/// it indicates an ANSII terminal color escape that should be used to
/// highlight the span's text. If it's `true`, it indicates that the text
/// should be highlighted using the default color. If it's `false` or `null`,
/// it indicates that the text shouldn't be highlighted.
String highlight({color});
}

/// A base class for source spans with [start], [end], and [text] known at
Expand Down
26 changes: 17 additions & 9 deletions lib/src/span_mixin.dart
Original file line number Diff line number Diff line change
Expand Up @@ -46,20 +46,26 @@ abstract class SourceSpanMixin implements SourceSpan {
}

String message(String message, {color}) {
if (color == true) color = colors.RED;
if (color == false) color = null;

var line = start.line;
var column = start.column;

var buffer = new StringBuffer();
buffer.write('line ${line + 1}, column ${column + 1}');
buffer.write('line ${start.line + 1}, column ${start.column + 1}');
if (sourceUrl != null) buffer.write(' of ${p.prettyUri(sourceUrl)}');
buffer.write(': $message');

if (length == 0 && this is! SourceSpanWithContext) return buffer.toString();
buffer.write("\n");
var highlight = this.highlight(color: color);
if (!highlight.isEmpty) {
buffer.writeln();
buffer.write(highlight);
}

return buffer.toString();
}

String highlight({color}) {
if (color == true) color = colors.RED;
if (color == false) color = null;

var column = start.column;
var buffer = new StringBuffer();
String textLine;
if (this is SourceSpanWithContext) {
var context = (this as SourceSpanWithContext).context;
Expand All @@ -71,6 +77,8 @@ abstract class SourceSpanMixin implements SourceSpan {
var endIndex = context.indexOf('\n');
textLine = endIndex == -1 ? context : context.substring(0, endIndex + 1);
column = math.min(column, textLine.length);
} else if (length == 0) {
return "";
} else {
textLine = text.split("\n").first;
column = 0;
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: source_span
version: 1.2.4
version: 1.3.0
author: Dart Team <[email protected]>
description: A library for identifying source spans and locations.
homepage: https://github.com/dart-lang/source_span
Expand Down
52 changes: 27 additions & 25 deletions test/file_message_test.dart → test/highlight_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,95 +13,97 @@ main() {
foo bar baz
whiz bang boom
zip zap zop
""", url: "foo.dart");
""");
});

test("points to the span in the source", () {
expect(file.span(4, 7).message("oh no"), equals("""
line 1, column 5 of foo.dart: oh no
expect(file.span(4, 7).highlight(), equals("""
foo bar baz
^^^"""));
});

test("gracefully handles a missing source URL", () {
var span = new SourceFile("foo bar baz").span(4, 7);
expect(span.message("oh no"), equals("""
line 1, column 5: oh no
expect(span.highlight(), equals("""
foo bar baz
^^^"""));
});

test("highlights the first line of a multiline span", () {
expect(file.span(4, 20).message("oh no"), equals("""
line 1, column 5 of foo.dart: oh no
expect(file.span(4, 20).highlight(), equals("""
foo bar baz
^^^^^^^^"""));
});

test("works for a point span", () {
expect(file.location(4).pointSpan().message("oh no"), equals("""
line 1, column 5 of foo.dart: oh no
expect(file.location(4).pointSpan().highlight(), equals("""
foo bar baz
^"""));
});

test("works for a point span at the end of a line", () {
expect(file.location(11).pointSpan().message("oh no"), equals("""
line 1, column 12 of foo.dart: oh no
expect(file.location(11).pointSpan().highlight(), equals("""
foo bar baz
^"""));
});

test("works for a point span at the end of the file", () {
expect(file.location(38).pointSpan().message("oh no"), equals("""
line 3, column 12 of foo.dart: oh no
expect(file.location(38).pointSpan().highlight(), equals("""
zip zap zop
^"""));
});

test("works for a point span at the end of the file with no trailing newline",
() {
file = new SourceFile("zip zap zop");
expect(file.location(11).pointSpan().message("oh no"), equals("""
line 1, column 12: oh no
expect(file.location(11).pointSpan().highlight(), equals("""
zip zap zop
^"""));
});

test("works for a point span in an empty file", () {
expect(new SourceFile("").location(0).pointSpan().message("oh no"),
expect(new SourceFile("").location(0).pointSpan().highlight(),
equals("""
line 1, column 1: oh no

^"""));
});

test("works for a single-line file without a newline", () {
expect(new SourceFile("foo bar").span(0, 7).message("oh no"),
expect(new SourceFile("foo bar").span(0, 7).highlight(),
equals("""
line 1, column 1: oh no
foo bar
^^^^^^^"""));
});

test("supports lines of preceding context", () {
var span = new SourceSpanWithContext(
new SourceLocation(5, line: 3, column: 5, sourceUrl: "foo.dart"),
new SourceLocation(12, line: 3, column: 12, sourceUrl: "foo.dart"),
"foo bar",
"previous\nlines\n-----foo bar-----\nfollowing line\n");

expect(span.highlight(color: colors.YELLOW), equals("""
previous
lines
-----${colors.YELLOW}foo bar${colors.NONE}-----
${colors.YELLOW}^^^^^^^${colors.NONE}"""));
});

group("colors", () {
test("doesn't colorize if color is false", () {
expect(file.span(4, 7).message("oh no", color: false), equals("""
line 1, column 5 of foo.dart: oh no
expect(file.span(4, 7).highlight(color: false), equals("""
foo bar baz
^^^"""));
});

test("colorizes if color is true", () {
expect(file.span(4, 7).message("oh no", color: true), equals("""
line 1, column 5 of foo.dart: oh no
expect(file.span(4, 7).highlight(color: true), equals("""
foo ${colors.RED}bar${colors.NONE} baz
${colors.RED}^^^${colors.NONE}"""));
});

test("uses the given color if it's passed", () {
expect(file.span(4, 7).message("oh no", color: colors.YELLOW), equals("""
line 1, column 5 of foo.dart: oh no
expect(file.span(4, 7).highlight(color: colors.YELLOW), equals("""
foo ${colors.YELLOW}bar${colors.NONE} baz
${colors.YELLOW}^^^${colors.NONE}"""));
});
Expand Down
36 changes: 2 additions & 34 deletions test/span_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -234,48 +234,16 @@ line 1, column 6 of foo.dart: oh no
${colors.YELLOW}foo bar${colors.NONE}
${colors.YELLOW}^^^^^^^${colors.NONE}"""));
});
});

group("message() with context", () {
var spanWithContext;
setUp(() {
spanWithContext = new SourceSpanWithContext(
test("with context, underlines the right column", () {
var spanWithContext = new SourceSpanWithContext(
new SourceLocation(5, sourceUrl: "foo.dart"),
new SourceLocation(12, sourceUrl: "foo.dart"),
"foo bar",
"-----foo bar-----");
});

test("underlines under the right column", () {
expect(spanWithContext.message("oh no", color: colors.YELLOW), equals("""
line 1, column 6 of foo.dart: oh no
-----${colors.YELLOW}foo bar${colors.NONE}-----
${colors.YELLOW}^^^^^^^${colors.NONE}"""));
});

test("underlines correctly when text appears twice", () {
var span = new SourceSpanWithContext(
new SourceLocation(9, column: 9, sourceUrl: "foo.dart"),
new SourceLocation(12, column: 12, sourceUrl: "foo.dart"),
"foo",
"-----foo foo-----");
expect(span.message("oh no", color: colors.YELLOW), equals("""
line 1, column 10 of foo.dart: oh no
-----foo ${colors.YELLOW}foo${colors.NONE}-----
${colors.YELLOW}^^^${colors.NONE}"""));
});

test("supports lines of preceeding context", () {
var span = new SourceSpanWithContext(
new SourceLocation(5, line: 3, column: 5, sourceUrl: "foo.dart"),
new SourceLocation(12, line: 3, column: 12, sourceUrl: "foo.dart"),
"foo bar",
"previous\nlines\n-----foo bar-----\nfollowing line\n");

expect(span.message("oh no", color: colors.YELLOW), equals("""
line 4, column 6 of foo.dart: oh no
previous
lines
-----${colors.YELLOW}foo bar${colors.NONE}-----
${colors.YELLOW}^^^^^^^${colors.NONE}"""));
});
Expand Down