commit d82683473da59e1cbf6a095ec68db6cfca92f4b1
parent 07e888e539e618dd5ccc16c0f0325d74d373a2b5
Author: Autumn! <autumnull@posteo.net>
Date: Wed, 15 Feb 2023 13:51:07 +0000
Add visual marker for errors
Signed-off-by: Autumn! <autumnull@posteo.net>
Diffstat:
5 files changed, 79 insertions(+), 0 deletions(-)
diff --git a/include/util.h b/include/util.h
@@ -30,4 +30,6 @@ struct pathspec {
char *getpath(const struct pathspec *paths, size_t npaths);
+int errline(const char* path, int lineno, int colno);
+
#endif
diff --git a/src/check.c b/src/check.c
@@ -51,9 +51,14 @@ static void
handle_errors(struct errors *errors)
{
struct errors *error = errors;
+ bool first = true;
while (error) {
fprintf(stderr, "Error %s:%d:%d: %s\n", sources[error->loc.file],
error->loc.lineno, error->loc.colno, error->msg);
+ if (first) {
+ errline(sources[error->loc.file], error->loc.lineno, error->loc.colno);
+ first = false;
+ }
struct errors *next = error->next;
free(error);
error = next;
diff --git a/src/lex.c b/src/lex.c
@@ -151,6 +151,7 @@ error(struct location *loc, char *fmt, ...)
va_end(ap);
fputc('\n', stderr);
+ errline(sources[loc->file], loc->lineno, loc->colno);
exit(EXIT_FAILURE);
}
diff --git a/src/parse.c b/src/parse.c
@@ -22,6 +22,7 @@ synassert_msg(bool cond, const char *msg, struct token *tok)
fprintf(stderr, "Syntax error: %s at %s:%d:%d (found '%s')\n", msg,
sources[tok->loc.file], tok->loc.lineno, tok->loc.colno,
token_str(tok));
+ errline(sources[tok->loc.file], tok->loc.lineno, tok->loc.colno);
exit(EXIT_FAILURE);
}
}
@@ -43,6 +44,7 @@ vsynerr(struct token *tok, va_list ap)
t = va_arg(ap, enum lexical_token);
fprintf(stderr, "%s", t == T_EOF ? "\n" : ", ");
}
+ errline(sources[tok->loc.file], tok->loc.lineno, tok->loc.colno);
exit(EXIT_FAILURE);
}
diff --git a/src/util.c b/src/util.c
@@ -1,7 +1,10 @@
+#include <sys/stat.h>
+#include <stdbool.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
+#include <unistd.h>
#include "util.h"
// Remove safety macros:
#undef malloc
@@ -117,3 +120,69 @@ getpath(const struct pathspec *paths, size_t npaths) {
}
return NULL;
}
+
+int
+errline(const char* path, int lineno, int colno)
+{
+ char* real = realpath(path, NULL);
+ struct stat filestat;
+ if (stat(real, &filestat) != 0 || !S_ISREG(filestat.st_mode)) {
+ free(real);
+ return -1;
+ }
+ free(real);
+
+ FILE* src = fopen(path, "r");
+ if (!src) {
+ return -1;
+ }
+ char* line = NULL;
+ size_t len = 0;
+ int n = 0;
+ while (n < lineno) {
+ if (getline(&line, &len, src) == -1) {
+ fclose(src);
+ if (line) {
+ free(line);
+ }
+ return -1;
+ }
+ n += 1;
+ }
+ if (line) {
+ bool color = true;
+ const char* no_color = getenv("NO_COLOR");
+ const char* harec_color = getenv("HAREC_COLOR");
+ if (!isatty(fileno(stderr))) {
+ color = false;
+ }
+ if (no_color != NULL) {
+ if (0 < strlen(no_color)) {
+ color = false;
+ }
+ }
+ if (harec_color != NULL) {
+ if (strcmp(harec_color, "0") == 0) {
+ color = false;
+ } else {
+ color = true;
+ }
+ }
+ fprintf(stderr, "\n%d |\t%s", lineno, line);
+ for (int i = lineno; 1 <= i; i /= 10) {
+ fputc(' ', stderr);
+ }
+ fputs(" |\t", stderr);
+ for (int i = 1; i < colno; i++) {
+ fputc(' ', stderr);
+ }
+ if (color) {
+ fputs("\x1b[31m^\x1b[0m\n\n", stderr);
+ } else {
+ fputs("^\n\n", stderr);
+ }
+ free(line);
+ }
+ fclose(src);
+ return 0;
+}