Skip to content

Commit e993a93

Browse files
authored
Merge pull request #2543 from mgreter/bugfix/unicode-aware-error-indicator
Make error indicator Unicode aware
2 parents a3b5d73 + 5c76806 commit e993a93

File tree

4 files changed

+45
-11
lines changed

4 files changed

+45
-11
lines changed

src/parser.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,15 @@ namespace Sass {
9999
// consume unicode BOM
100100
read_bom();
101101

102+
// scan the input to find invalid utf8 sequences
103+
const char* it = utf8::find_invalid(position, end);
104+
105+
// report invalid utf8
106+
if (it != end) {
107+
pstate += Offset::init(position, it);
108+
throw Exception::InvalidSass(pstate, "Invalid UTF-8 sequence");
109+
}
110+
102111
// create a block AST node to hold children
103112
Block_Obj root = SASS_MEMORY_NEW(Block, pstate, 0, true);
104113

src/sass_context.cpp

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -72,24 +72,35 @@ namespace Sass {
7272

7373
// now create the code trace (ToDo: maybe have util functions?)
7474
if (e.pstate.line != std::string::npos && e.pstate.column != std::string::npos) {
75-
size_t line = e.pstate.line;
75+
size_t lines = e.pstate.line;
7676
const char* line_beg = e.pstate.src;
77-
while (line_beg && *line_beg && line) {
78-
if (*line_beg == '\n') --line;
79-
++line_beg;
77+
// scan through src until target line
78+
// move line_beg pointer to line start
79+
while (line_beg && *line_beg && lines != 0) {
80+
if (*line_beg == '\n') --lines;
81+
utf8::unchecked::next(line_beg);
8082
}
8183
const char* line_end = line_beg;
84+
// move line_end before next newline character
8285
while (line_end && *line_end && *line_end != '\n') {
8386
if (*line_end == '\n') break;
8487
if (*line_end == '\r') break;
85-
line_end++;
88+
utf8::unchecked::next(line_end);
8689
}
87-
size_t max_left = 42; size_t max_right = 78;
88-
size_t move_in = e.pstate.column > max_left ? e.pstate.column - max_left : 0;
89-
size_t shorten = (line_end - line_beg) - move_in > max_right ?
90-
(line_end - line_beg) - move_in - max_right : 0;
91-
msg_stream << ">> " << std::string(line_beg + move_in, line_end - shorten) << "\n";
92-
msg_stream << " " << std::string(e.pstate.column - move_in, '-') << "^\n";
90+
if (line_end && *line_end != 0) ++ line_end;
91+
size_t line_len = line_end - line_beg;
92+
size_t move_in = 0; size_t shorten = 0;
93+
size_t left_chars = 42; size_t max_chars = 76;
94+
// reported excerpt should not exceed `max_chars` chars
95+
if (e.pstate.column > line_len) left_chars = e.pstate.column;
96+
if (e.pstate.column > left_chars) move_in = e.pstate.column - left_chars;
97+
if (line_len > max_chars + move_in) shorten = line_len - move_in - max_chars;
98+
utf8::advance(line_beg, move_in, line_end);
99+
utf8::retreat(line_end, shorten, line_beg);
100+
std::string sanitized; std::string marker(e.pstate.column - move_in, '-');
101+
utf8::replace_invalid(line_beg, line_end, std::back_inserter(sanitized));
102+
msg_stream << ">> " << sanitized << "\n";
103+
msg_stream << " " << marker << "^\n";
93104
}
94105

95106
JsonNode* json_err = json_mkobject();

src/utf8/checked.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,13 @@ namespace utf8
193193
utf8::next(it, end);
194194
}
195195

196+
template <typename octet_iterator, typename distance_type>
197+
void retreat (octet_iterator& it, distance_type n, octet_iterator start)
198+
{
199+
for (distance_type i = 0; i < n; ++i)
200+
utf8::prior(it, start);
201+
}
202+
196203
template <typename octet_iterator>
197204
typename std::iterator_traits<octet_iterator>::difference_type
198205
distance (octet_iterator first, octet_iterator last)

src/utf8/unchecked.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,13 @@ namespace utf8
116116
utf8::unchecked::next(it);
117117
}
118118

119+
template <typename octet_iterator, typename distance_type>
120+
void retreat (octet_iterator& it, distance_type n)
121+
{
122+
for (distance_type i = 0; i < n; ++i)
123+
utf8::unchecked::prior(it);
124+
}
125+
119126
template <typename octet_iterator>
120127
typename std::iterator_traits<octet_iterator>::difference_type
121128
distance (octet_iterator first, octet_iterator last)

0 commit comments

Comments
 (0)