diff options
Diffstat (limited to 'src/debug.c')
-rw-r--r-- | src/debug.c | 83 |
1 files changed, 58 insertions, 25 deletions
diff --git a/src/debug.c b/src/debug.c index c146719..0f0e0fe 100644 --- a/src/debug.c +++ b/src/debug.c @@ -3,16 +3,7 @@ #include <posthaste/debug.h> -/** - * Find position in file buffer where line number \p no - * starts. Lines are assumed to be one-indexed, with - * \p no = \c 0 and \p no = \c 1 both considered the first line. - * - * @param buf Buffer to look in. - * @param no Line number whose start to look for. - * @return Pointer to location in buffer where line number \p no - * starts. - */ +/* find the start of line number no in buffer buf */ static const char *find_lineno(const char *buf, size_t no) { if (no == 0 || no == 1) @@ -32,37 +23,79 @@ static const char *find_lineno(const char *buf, size_t no) return buf; } -void vsrc_issue(struct src_issue issue, const char *msg, va_list args) +static void print_bar(int lineno_len) { - const char *line_start = find_lineno(issue.buf, issue.loc.first_line); - const char *line_end = strchr(line_start, '\n'); - if (!line_end) - line_end = strchr(line_start, 0); + fprintf(stderr, "%*s", lineno_len + 4, "| "); +} + +static void vsrc_multi_line(struct src_issue issue, const char *line_start, int lineno_len) +{ + /* just dump lines as they are, adding bars to the left */ + size_t line = issue.loc.first_line; + for (size_t i = 0;; ++i) { + char c = line_start[i]; + if (c == 0) { + fputc('\n', stderr); + break; + } + + fputc(c, stderr); + + + if (c == '\n') { + if (++line > issue.loc.last_line) + break; + + print_bar(lineno_len); + } + } +} - int line_len = line_end - line_start; +void vsrc_issue(struct src_issue issue, const char *msg, va_list args) +{ + /* with color support we could start coloring the actual error region at + * issue.loc.first_column on issue.loc.first_line, but messing with + * xterm color codes is a bit cumbersome so for now just stick to + * monochrome */ - fprintf(stderr, "%s:%i:%i: ", issue.fname, + fprintf(stderr, "%s:%i:%i: ", + issue.fname, issue.loc.first_line, issue.loc.first_col); vfprintf(stderr, msg, args); fputc('\n', stderr); + /* figure out how many spaces line number takes up */ int lineno_len = snprintf(NULL, 0, "%i", issue.loc.first_line); - fputc(' ', stderr); - fprintf(stderr, "%i | ", issue.loc.first_line); + fprintf(stderr, " %i | ", issue.loc.first_line); + + const char *line_start = find_lineno(issue.buf, issue.loc.first_line); + if (issue.loc.first_line != issue.loc.last_line) { + /* multiline location requires slightly different handling */ + return vsrc_multi_line(issue, line_start, lineno_len); + } - fprintf(stderr, "%.*s\n", line_len, line_start); + /* print the offending line */ + for (size_t i = 0;; ++i) { + char c = line_start[i]; + if (c == 0 || c == '\n') + break; - for (int i = 0; i < lineno_len + 2; ++i) - fputc(' ', stderr); + fputc(c, stderr); + } + fputc('\n', stderr); - fprintf(stderr, "| "); + /* the rest is just to print a little squiggly line to highlight exact location */ + print_bar(lineno_len); - for (int i = 0; i < issue.loc.first_col - 1; ++i) + /* print tabs on tabs, otherwise spaces to make start of squiggle line + * up with start of offending location */ + for (size_t i = 0; i < issue.loc.first_col - 1; ++i) fputc(line_start[i] == '\t' ? '\t' : ' ', stderr); - for (int i = issue.loc.first_col; i < issue.loc.last_col; ++i) { + /* highlight the offending location */ + for (size_t i = issue.loc.first_col; i < issue.loc.last_col; ++i) { if (i == issue.loc.first_col) fputc('^', stderr); else |