summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Newton <kddnewton@gmail.com>2024-05-16 15:07:03 -0400
committergit <svn-admin@ruby-lang.org>2024-05-16 19:35:10 +0000
commit92af7054989e6bb605482178f97cee5e59ec9326 (patch)
tree2d8bc027af3d01d937e544dc8794546d9c8a0454
parent98e1e610f6df95aa89481fd92a31a75a808ce2d1 (diff)
[ruby/prism] Truncate source lines in errors messages when too long
https://github.com/ruby/prism/commit/72518f5716
-rw-r--r--prism/prism.c48
-rw-r--r--test/prism/format_errors_test.rb42
-rw-r--r--test/prism/newline_test.rb1
3 files changed, 80 insertions, 11 deletions
diff --git a/prism/prism.c b/prism/prism.c
index 75f1432161..d203b4b720 100644
--- a/prism/prism.c
+++ b/prism/prism.c
@@ -21592,6 +21592,7 @@ typedef struct {
#define PM_COLOR_GRAY "\033[38;5;102m"
#define PM_COLOR_RED "\033[1;31m"
#define PM_COLOR_RESET "\033[m"
+#define PM_ERROR_TRUNCATE 30
static inline pm_error_t *
pm_parser_errors_format_sort(const pm_parser_t *parser, const pm_list_t *error_list, const pm_newline_list_t *newline_list) {
@@ -21646,7 +21647,7 @@ pm_parser_errors_format_sort(const pm_parser_t *parser, const pm_list_t *error_l
}
static inline void
-pm_parser_errors_format_line(const pm_parser_t *parser, const pm_newline_list_t *newline_list, const char *number_prefix, int32_t line, pm_buffer_t *buffer) {
+pm_parser_errors_format_line(const pm_parser_t *parser, const pm_newline_list_t *newline_list, const char *number_prefix, int32_t line, uint32_t column_start, uint32_t column_end, pm_buffer_t *buffer) {
int32_t line_delta = line - parser->start_line;
assert(line_delta >= 0);
@@ -21663,9 +21664,25 @@ pm_parser_errors_format_line(const pm_parser_t *parser, const pm_newline_list_t
}
pm_buffer_append_format(buffer, number_prefix, line);
+
+ // Here we determine if we should truncate the end of the line.
+ bool truncate_end = false;
+ if ((column_end != 0) && ((end - (start + column_end)) >= PM_ERROR_TRUNCATE)) {
+ end = start + column_end + PM_ERROR_TRUNCATE;
+ truncate_end = true;
+ }
+
+ // Here we determine if we should truncate the start of the line.
+ if (column_start >= PM_ERROR_TRUNCATE) {
+ pm_buffer_append_string(buffer, "... ", 4);
+ start += column_start;
+ }
+
pm_buffer_append_string(buffer, (const char *) start, (size_t) (end - start));
- if (end == parser->end && end[-1] != '\n') {
+ if (truncate_end) {
+ pm_buffer_append_string(buffer, " ...\n", 5);
+ } else if (end == parser->end && end[-1] != '\n') {
pm_buffer_append_string(buffer, "\n", 1);
}
}
@@ -21780,6 +21797,7 @@ pm_parser_errors_format(const pm_parser_t *parser, const pm_list_t *error_list,
// display the same line twice in case the errors are close enough in the
// source.
int32_t last_line = parser->start_line - 1;
+ uint32_t last_column_start = 0;
const pm_encoding_t *encoding = parser->encoding;
for (size_t index = 0; index < error_list->size; index++) {
@@ -21794,11 +21812,11 @@ pm_parser_errors_format(const pm_parser_t *parser, const pm_list_t *error_list,
}
pm_buffer_append_string(buffer, " ", 2);
- pm_parser_errors_format_line(parser, newline_list, error_format.number_prefix, error->line - 2, buffer);
+ pm_parser_errors_format_line(parser, newline_list, error_format.number_prefix, error->line - 2, 0, 0, buffer);
}
pm_buffer_append_string(buffer, " ", 2);
- pm_parser_errors_format_line(parser, newline_list, error_format.number_prefix, error->line - 1, buffer);
+ pm_parser_errors_format_line(parser, newline_list, error_format.number_prefix, error->line - 1, 0, 0, buffer);
}
// If this is the first error or we're on a new line, then we'll display
@@ -21809,7 +21827,17 @@ pm_parser_errors_format(const pm_parser_t *parser, const pm_list_t *error_list,
} else {
pm_buffer_append_string(buffer, "> ", 2);
}
- pm_parser_errors_format_line(parser, newline_list, error_format.number_prefix, error->line, buffer);
+
+ last_column_start = error->column_start;
+
+ // Find the maximum column end of all the errors on this line.
+ uint32_t column_end = error->column_end;
+ for (size_t next_index = index + 1; next_index < error_list->size; next_index++) {
+ if (errors[next_index].line != error->line) break;
+ if (errors[next_index].column_end > column_end) column_end = errors[next_index].column_end;
+ }
+
+ pm_parser_errors_format_line(parser, newline_list, error_format.number_prefix, error->line, error->column_start, column_end, buffer);
}
const uint8_t *start = &parser->start[newline_list->offsets[error->line - start_line]];
@@ -21828,6 +21856,11 @@ pm_parser_errors_format(const pm_parser_t *parser, const pm_list_t *error_list,
pm_buffer_append_string(buffer, error_format.blank_prefix, error_format.blank_prefix_length);
size_t column = 0;
+ if (last_column_start >= PM_ERROR_TRUNCATE) {
+ pm_buffer_append_string(buffer, " ", 4);
+ column = last_column_start;
+ }
+
while (column < error->column_start) {
pm_buffer_append_byte(buffer, ' ');
@@ -21867,12 +21900,12 @@ pm_parser_errors_format(const pm_parser_t *parser, const pm_list_t *error_list,
if (next_line - last_line > 1) {
pm_buffer_append_string(buffer, " ", 2);
- pm_parser_errors_format_line(parser, newline_list, error_format.number_prefix, ++last_line, buffer);
+ pm_parser_errors_format_line(parser, newline_list, error_format.number_prefix, ++last_line, 0, 0, buffer);
}
if (next_line - last_line > 1) {
pm_buffer_append_string(buffer, " ", 2);
- pm_parser_errors_format_line(parser, newline_list, error_format.number_prefix, ++last_line, buffer);
+ pm_parser_errors_format_line(parser, newline_list, error_format.number_prefix, ++last_line, 0, 0, buffer);
}
}
@@ -21880,6 +21913,7 @@ pm_parser_errors_format(const pm_parser_t *parser, const pm_list_t *error_list,
xfree(errors);
}
+#undef PM_ERROR_TRUNCATE
#undef PM_COLOR_GRAY
#undef PM_COLOR_RED
#undef PM_COLOR_RESET
diff --git a/test/prism/format_errors_test.rb b/test/prism/format_errors_test.rb
index a1edbef2e8..63206d5765 100644
--- a/test/prism/format_errors_test.rb
+++ b/test/prism/format_errors_test.rb
@@ -6,19 +6,53 @@ return if Prism::BACKEND == :FFI
module Prism
class FormatErrorsTest < TestCase
- def test_format_errors
- assert_equal <<~ERROR, Debug.format_errors("<>", false)
+ def test_basic
+ expected = <<~ERROR
> 1 | <>
| ^ unexpected '<', ignoring it
| ^ unexpected '>', ignoring it
ERROR
- assert_equal <<~'ERROR', Debug.format_errors('"%W"\u"', false)
- > 1 | "%W"\u"
+ assert_equal expected, Debug.format_errors("<>", false)
+ end
+
+ def test_multiple
+ expected = <<~ERROR
+ > 1 | "%W"\\u"
| ^ unexpected backslash, ignoring it
| ^ unexpected local variable or method, expecting end-of-input
| ^ unterminated string meets end of file
ERROR
+
+ assert_equal expected, Debug.format_errors('"%W"\u"', false)
+ end
+
+ def test_truncate_start
+ expected = <<~ERROR
+ > 1 | ... <>
+ | ^ unexpected '<', ignoring it
+ | ^ unexpected '>', ignoring it
+ ERROR
+
+ assert_equal expected, Debug.format_errors("#{" " * 30}<>", false)
+ end
+
+ def test_truncate_end
+ expected = <<~ERROR
+ > 1 | <#{" " * 30} ...
+ | ^ unexpected '<', ignoring it
+ ERROR
+
+ assert_equal expected, Debug.format_errors("<#{" " * 30}a", false)
+ end
+
+ def test_truncate_both
+ expected = <<~ERROR
+ > 1 | ... <#{" " * 30} ...
+ | ^ unexpected '<', ignoring it
+ ERROR
+
+ assert_equal expected, Debug.format_errors("#{" " * 30}<#{" " * 30}a", false)
end
end
end
diff --git a/test/prism/newline_test.rb b/test/prism/newline_test.rb
index d31fb89bc6..f7511f665c 100644
--- a/test/prism/newline_test.rb
+++ b/test/prism/newline_test.rb
@@ -10,6 +10,7 @@ module Prism
filepaths = Dir["*.rb", base: base] - %w[
encoding_test.rb
errors_test.rb
+ format_errors_test.rb
parser_test.rb
regexp_test.rb
static_literals_test.rb