From 70d8fbd33dc5d9e33a13fe4abe03f62a5641e701 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Tue, 12 Jul 2022 16:54:36 -0700 Subject: [PATCH] Properly indent multi-line labels for mutli-span highlights --- CHANGELOG.md | 4 +- lib/src/highlighter.dart | 47 +++++++++++++++--- pubspec.yaml | 2 +- test/multiple_highlight_test.dart | 80 +++++++++++++++++++++++++++++++ 4 files changed, 124 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5722045..4c49079 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,6 @@ -# 1.9.1-dev +# 1.9.1 + +* Properly handle multi-line labels for multi-span highlights. * Populate the pubspec `repository` field. diff --git a/lib/src/highlighter.dart b/lib/src/highlighter.dart index d4e5ebf..1dedfdb 100644 --- a/lib/src/highlighter.dart +++ b/lib/src/highlighter.dart @@ -361,6 +361,7 @@ class Highlighter { void _writeIndicator( _Line line, _Highlight highlight, List<_Highlight?> highlightsByColumn) { final color = highlight.isPrimary ? _primaryColor : _secondaryColor; + final start = _buffer.length; if (!isMultiline(highlight.span)) { _writeSidebar(); _buffer.write(' '); @@ -370,9 +371,8 @@ class Highlighter { _colorize(() { _writeUnderline(line, highlight.span, highlight.isPrimary ? '^' : glyph.horizontalLineBold); - _writeLabel(highlight.label); }, color: color); - _buffer.writeln(); + _writeLabel(highlight, highlightsByColumn, start); } else if (highlight.span.start.line == line.number) { if (highlightsByColumn.contains(highlight)) return; replaceFirstNull(highlightsByColumn, highlight); @@ -401,9 +401,8 @@ class Highlighter { _writeArrow(line, math.max(highlight.span.end.column - 1, 0), beginning: false); } - _writeLabel(highlight.label); }, color: color); - _buffer.writeln(); + _writeLabel(highlight, highlightsByColumn, start); replaceWithNull(highlightsByColumn, highlight); } } @@ -442,9 +441,43 @@ class Highlighter { ..write('^'); } - /// Writes a space followed by [label] if [label] isn't `null`. - void _writeLabel(String? label) { - if (label != null) _buffer.write(' $label'); + /// Writes [highlight]'s label. + /// + /// The `_buffer` is assumed to be written to the point where the first line + /// of `highlight.label` can be written after a space, but this takes care of + /// writing indentation and highlight columns for later lines. + /// + /// The [start] is the position in [_buffer] at the start of the current line. + void _writeLabel( + _Highlight highlight, List<_Highlight?> highlightsByColumn, int start) { + final label = highlight.label; + if (label == null) { + _buffer.writeln(); + return; + } + + final lines = label.split('\n'); + final color = highlight.isPrimary ? _primaryColor : _secondaryColor; + final column = _buffer.length - start; + _colorize(() => _buffer.write(' ${lines.first}'), color: color); + _buffer.writeln(); + + for (var text in lines.skip(1)) { + final lineStart = _buffer.length; + _writeSidebar(); + _buffer.write(' '); + for (var columnHighlight in highlightsByColumn) { + if (columnHighlight == null || columnHighlight == highlight) { + _buffer.write(' '); + } else { + _buffer.write(glyph.verticalLine); + } + } + + _buffer.write(' ' * (column - (_buffer.length - lineStart))); + _colorize(() => _buffer.write(' $text'), color: color); + _buffer.writeln(); + } } /// Writes a snippet from the source text, converting hard tab characters into diff --git a/pubspec.yaml b/pubspec.yaml index 63a64b0..8bde1c2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: source_span -version: 1.9.1-dev +version: 1.9.1 description: A library for identifying source spans and locations. repository: https://github.com/dart-lang/source_span diff --git a/test/multiple_highlight_test.dart b/test/multiple_highlight_test.dart index a9f5fda..fa33df1 100644 --- a/test/multiple_highlight_test.dart +++ b/test/multiple_highlight_test.dart @@ -328,4 +328,84 @@ quibble bibble boop | === two '""")); }); + + group('indents mutli-line labels', () { + test('for the primary label', () { + expect(file.span(17, 21).highlightMultiple('line 1\nline 2\nline 3', {}), + equals(""" + , +2 | whiz bang boom + | ^^^^ line 1 + | line 2 + | line 3 + '""")); + }); + + test('for a secondary label', () { + expect( + file.span(17, 21).highlightMultiple( + 'primary', {file.span(31, 34): 'line 1\nline 2\nline 3'}), + equals(""" + , +2 | whiz bang boom + | ^^^^ primary +3 | zip zap zop + | === line 1 + | line 2 + | line 3 + '""")); + }); + + group('for a multiline span', () { + test('that covers the whole last line', () { + expect( + file.span(12, 70).highlightMultiple('line 1\nline 2\nline 3', {}), + equals(""" + , +2 | / whiz bang boom +3 | | zip zap zop +4 | | fwee fwoo fwip +5 | | argle bargle boo + | '--- line 1 + | line 2 + | line 3 + '""")); + }); + + test('that covers part of the last line', () { + expect( + file.span(12, 66).highlightMultiple('line 1\nline 2\nline 3', {}), + equals(""" + , +2 | / whiz bang boom +3 | | zip zap zop +4 | | fwee fwoo fwip +5 | | argle bargle boo + | '------------^ line 1 + | line 2 + | line 3 + '""")); + }); + }); + + test('with an overlapping span', () { + expect( + file.span(12, 70).highlightMultiple('line 1\nline 2\nline 3', + {file.span(54, 89): 'two', file.span(0, 27): 'three'}), + equals(""" + , +1 | /- foo bar baz +2 | |/ whiz bang boom + | '+--- three +3 | | zip zap zop +4 | | fwee fwoo fwip +5 | /+ argle bargle boo + | |'--- line 1 + | | line 2 + | | line 3 +6 | | gibble bibble bop + | '---- two + '""")); + }); + }); }