Refactor highlighter normalizations
diff --git a/lib/src/highlighter.dart b/lib/src/highlighter.dart
index 97d696d..6270912 100644
--- a/lib/src/highlighter.dart
+++ b/lib/src/highlighter.dart
@@ -58,66 +58,75 @@
if (color == true) color = colors.RED;
if (color == false) color = null;
- // Normalize [span] to ensure that it's a [SourceSpanWithContext] whose
- // context actually contains its text at the expected column. If it's not,
- // adjust the start and end locations' line and column fields so that the
- // highlighter can assume they match up with the context.
- SourceSpanWithContext newSpan;
- if (span is SourceSpanWithContext &&
- findLineStart(span.context, span.text, span.start.column) != null) {
- newSpan = span;
- } else {
- newSpan = new SourceSpanWithContext(
- new SourceLocation(span.start.offset,
- sourceUrl: span.sourceUrl, line: 0, column: 0),
- new SourceLocation(span.end.offset,
- sourceUrl: span.sourceUrl,
- line: countCodeUnits(span.text, $lf),
- column: _lastColumn(span.text)),
- span.text,
- span.text);
- }
-
- // Normalize [span] to remove a trailing newline from `span.context`. If
- // necessary, also adjust `span.end` so that it doesn't point past where the
- // trailing newline used to be.
- if (newSpan.context.endsWith("\n")) {
- var context = newSpan.context.substring(0, newSpan.context.length - 1);
-
- var text = newSpan.text;
- var start = newSpan.start;
- var end = newSpan.end;
- if (newSpan.text.endsWith("\n") && _isTextAtEndOfContext(newSpan)) {
- text = newSpan.text.substring(0, newSpan.text.length - 1);
- end = new SourceLocation(newSpan.end.offset - 1,
- sourceUrl: newSpan.sourceUrl,
- line: newSpan.end.line - 1,
- column: _lastColumn(text));
- start =
- newSpan.start.offset == newSpan.end.offset ? end : newSpan.start;
- }
- newSpan = new SourceSpanWithContext(start, end, text, context);
- }
-
- // Normalize [span] so that the end location is at the end of a line, rather
- // than on the beginning of the next line.
- if (newSpan.end.column == 0 && newSpan.end.line != newSpan.start.line) {
- assert(newSpan.text.endsWith("\n"));
-
- var text = newSpan.text.substring(0, newSpan.text.length - 1);
- newSpan = new SourceSpanWithContext(
- newSpan.start,
- new SourceLocation(span.end.offset - 1,
- sourceUrl: span.sourceUrl,
- line: span.end.line - 1,
- column: _lastColumn(text)),
- text,
- newSpan.context);
- }
+ var newSpan = _normalizeContext(span);
+ newSpan = _normalizeTrailingNewline(newSpan);
+ newSpan = _normalizeEndOfLine(newSpan);
return new Highlighter._(newSpan, color);
}
+ /// Normalizes [span] to ensure that it's a [SourceSpanWithContext] whose
+ /// context actually contains its text at the expected column.
+ ///
+ /// If it's not already a [SourceSpanWithContext], adjust the start and end
+ /// locations' line and column fields so that the highlighter can assume they
+ /// match up with the context.
+ static SourceSpanWithContext _normalizeContext(SourceSpan span) =>
+ span is SourceSpanWithContext &&
+ findLineStart(span.context, span.text, span.start.column) != null
+ ? span
+ : new SourceSpanWithContext(
+ new SourceLocation(span.start.offset,
+ sourceUrl: span.sourceUrl, line: 0, column: 0),
+ new SourceLocation(span.end.offset,
+ sourceUrl: span.sourceUrl,
+ line: countCodeUnits(span.text, $lf),
+ column: _lastColumn(span.text)),
+ span.text,
+ span.text);
+
+ /// Normalizes [span] to remove a trailing newline from `span.context`.
+ ///
+ /// If necessary, also adjust `span.end` so that it doesn't point past where
+ /// the trailing newline used to be.
+ static SourceSpanWithContext _normalizeTrailingNewline(
+ SourceSpanWithContext span) {
+ if (!span.context.endsWith("\n")) return span;
+
+ var context = span.context.substring(0, span.context.length - 1);
+ var text = span.text;
+ var start = span.start;
+ var end = span.end;
+ if (span.text.endsWith("\n") && _isTextAtEndOfContext(span)) {
+ text = span.text.substring(0, span.text.length - 1);
+ end = new SourceLocation(span.end.offset - 1,
+ sourceUrl: span.sourceUrl,
+ line: span.end.line - 1,
+ column: _lastColumn(text));
+ start = span.start.offset == span.end.offset ? end : span.start;
+ }
+ return new SourceSpanWithContext(start, end, text, context);
+ }
+
+ /// Normalizes [span] so that the end location is at the end of a line, rather
+ /// than on the beginning of the next line.
+ static SourceSpanWithContext _normalizeEndOfLine(SourceSpanWithContext span) {
+ if (span.end.column != 0) return span;
+ if (span.end.line == span.start.line) return span;
+
+ assert(span.text.endsWith("\n"));
+
+ var text = span.text.substring(0, span.text.length - 1);
+ return new SourceSpanWithContext(
+ span.start,
+ new SourceLocation(span.end.offset - 1,
+ sourceUrl: span.sourceUrl,
+ line: span.end.line - 1,
+ column: _lastColumn(text)),
+ text,
+ span.context);
+ }
+
/// Returns the (0-based) column number of the last column of the last line in [text].
static int _lastColumn(String text) =>
text.length - text.lastIndexOf("\n") + 1;
@@ -147,7 +156,7 @@
// on, write those first.
var lineStart =
findLineStart(_span.context, _span.text, _span.start.column);
- assert(lineStart != null); // enforced by [new Highlighter]
+ assert(lineStart != null); // enforced by [_normalizeContext]
var context = _span.context;
if (lineStart > 0) {