Add SourceSpan.highlight(). (#10)
This is useful for constructing a message with a non-standard
file/line/column display.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6da8487..afcc493 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -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.
diff --git a/lib/src/span.dart b/lib/src/span.dart
index fe1ac39..599d668 100644
--- a/lib/src/span.dart
+++ b/lib/src/span.dart
@@ -53,6 +53,19 @@
/// 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
diff --git a/lib/src/span_mixin.dart b/lib/src/span_mixin.dart
index a258cf5..8d84cea 100644
--- a/lib/src/span_mixin.dart
+++ b/lib/src/span_mixin.dart
@@ -46,20 +46,26 @@
}
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;
@@ -71,6 +77,8 @@
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;
diff --git a/pubspec.yaml b/pubspec.yaml
index 9e41fdd..8fa8711 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
name: source_span
-version: 1.2.4
+version: 1.3.0
author: Dart Team <misc@dartlang.org>
description: A library for identifying source spans and locations.
homepage: https://github.com/dart-lang/source_span
diff --git a/test/file_message_test.dart b/test/file_message_test.dart
deleted file mode 100644
index d78a651..0000000
--- a/test/file_message_test.dart
+++ /dev/null
@@ -1,109 +0,0 @@
-// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'package:test/test.dart';
-import 'package:source_span/source_span.dart';
-import 'package:source_span/src/colors.dart' as colors;
-
-main() {
- var file;
- setUp(() {
- file = new SourceFile("""
-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
-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
-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
-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
-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
-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
-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
-zip zap zop
- ^"""));
- });
-
- test("works for a point span in an empty file", () {
- expect(new SourceFile("").location(0).pointSpan().message("oh no"),
- 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"),
- equals("""
-line 1, column 1: oh no
-foo bar
-^^^^^^^"""));
- });
-
- 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
-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
-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
-foo ${colors.YELLOW}bar${colors.NONE} baz
- ${colors.YELLOW}^^^${colors.NONE}"""));
- });
- });
-}
diff --git a/test/highlight_test.dart b/test/highlight_test.dart
new file mode 100644
index 0000000..32b09ff
--- /dev/null
+++ b/test/highlight_test.dart
@@ -0,0 +1,111 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:test/test.dart';
+import 'package:source_span/source_span.dart';
+import 'package:source_span/src/colors.dart' as colors;
+
+main() {
+ var file;
+ setUp(() {
+ file = new SourceFile("""
+foo bar baz
+whiz bang boom
+zip zap zop
+""");
+ });
+
+ test("points to the span in the source", () {
+ 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.highlight(), equals("""
+foo bar baz
+ ^^^"""));
+ });
+
+ test("highlights the first line of a multiline span", () {
+ expect(file.span(4, 20).highlight(), equals("""
+foo bar baz
+ ^^^^^^^^"""));
+ });
+
+ test("works for a point span", () {
+ 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().highlight(), equals("""
+foo bar baz
+ ^"""));
+ });
+
+ test("works for a point span at the end of the file", () {
+ 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().highlight(), equals("""
+zip zap zop
+ ^"""));
+ });
+
+ test("works for a point span in an empty file", () {
+ expect(new SourceFile("").location(0).pointSpan().highlight(),
+ equals("""
+
+^"""));
+ });
+
+ test("works for a single-line file without a newline", () {
+ expect(new SourceFile("foo bar").span(0, 7).highlight(),
+ equals("""
+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).highlight(color: false), equals("""
+foo bar baz
+ ^^^"""));
+ });
+
+ test("colorizes if color is true", () {
+ 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).highlight(color: colors.YELLOW), equals("""
+foo ${colors.YELLOW}bar${colors.NONE} baz
+ ${colors.YELLOW}^^^${colors.NONE}"""));
+ });
+ });
+}
diff --git a/test/span_test.dart b/test/span_test.dart
index 113848a..f980f30 100644
--- a/test/span_test.dart
+++ b/test/span_test.dart
@@ -234,51 +234,19 @@
${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}"""));
- });
});
group("compareTo()", () {