feat render error messages inside the code
This commit is contained in:
parent
83b4df1408
commit
5a1e4d5897
@ -1,7 +1,7 @@
|
|||||||
import { spawn } from "node:child_process";
|
import { spawn } from "node:child_process";
|
||||||
import { leftTrimDedent } from "../components/utils";
|
import { leftTrimDedent } from "../components/utils";
|
||||||
import { HighlightLevel } from "./types";
|
import { HighlightLevel } from "./types";
|
||||||
import type { MistiErr, Token, TokenizeResult, TokenType } from "./types";
|
import type { ErrorLabel, MistiErr, Token, TokenizeResult, TokenType } from "./types";
|
||||||
|
|
||||||
const error_classes = "underline underline-offset-4 decoration-wavy decoration-red-500";
|
const error_classes = "underline underline-offset-4 decoration-wavy decoration-red-500";
|
||||||
|
|
||||||
@ -39,7 +39,7 @@ function highlight_syntax(code: string, result: TokenizeResult): [string, string
|
|||||||
const [tokens, errors] = result.MixedErr;
|
const [tokens, errors] = result.MixedErr;
|
||||||
// TODO: Implement error rendering, based on the new error schema
|
// TODO: Implement error rendering, based on the new error schema
|
||||||
|
|
||||||
const tokens_html = render_tokens(code, tokens);
|
const tokens_html = render_tokens(code, tokens, errors.labels);
|
||||||
return [tokens_html, `error code ${errors.error_code}`];
|
return [tokens_html, `error code ${errors.error_code}`];
|
||||||
} else if (result.Err) {
|
} else if (result.Err) {
|
||||||
// TODO: Implement error rendering, based on the new error schema
|
// TODO: Implement error rendering, based on the new error schema
|
||||||
@ -60,25 +60,37 @@ function compiler_error(code: string, error: MistiErr): [string, string] {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transforms a list of tokens into colored HTML, and underlines errors
|
* Transforms a list of tokens into colored HTML, and underlines present errors
|
||||||
* if present
|
*
|
||||||
* @param input The original source code
|
* @param input The original source code
|
||||||
* @param tokens The list of tokens
|
* @param tokens The list of tokens
|
||||||
* @param error_start Absolute position from where the error starts.
|
* @param error_start Absolute position from where the error starts.
|
||||||
* @param error_end Absolute position to where the error ends.
|
* @param error_end Absolute position to where the error ends.
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
function render_tokens(input: string, tokens: Array<Token>, error_start = -1, error_end = -1): string {
|
function render_tokens(input: string, tokens: Array<Token>, error_labels: Array<ErrorLabel> = []): string {
|
||||||
const input_chars = input.split("");
|
const input_chars = input.split("");
|
||||||
let output = "";
|
let output = "";
|
||||||
|
|
||||||
|
// Collects all the token ranges in all error labels
|
||||||
|
const error_ranges: Array<[number, number]> = error_labels.map(l => [l.start, l.end]);
|
||||||
|
|
||||||
let current_pos = 0;
|
let current_pos = 0;
|
||||||
for (let i = 0; i < tokens.length; i += 1) {
|
for (let i = 0; i < tokens.length; i += 1) {
|
||||||
const t = tokens[i]!;
|
const t = tokens[i]!;
|
||||||
const token_start = t.position;
|
const token_start = t.position;
|
||||||
const token_end = t.position + t.value.length;
|
const token_end = t.position + t.value.length;
|
||||||
|
|
||||||
let is_errored = (token_start >= error_start && token_end <= error_end);
|
// check if the current token is in any error label
|
||||||
|
let is_errored = false;
|
||||||
|
for (const range of error_ranges) {
|
||||||
|
const [error_start, error_end] = range;
|
||||||
|
|
||||||
|
if (token_start >= error_start && token_end <= error_end) {
|
||||||
|
is_errored = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Some tokens require processing (like multiline comments)
|
// Some tokens require processing (like multiline comments)
|
||||||
|
|
||||||
@ -98,7 +110,25 @@ function render_tokens(input: string, tokens: Array<Token>, error_start = -1, er
|
|||||||
current_pos = new_token_end;
|
current_pos = new_token_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
return output;
|
// at this point `output` is a string with tokens
|
||||||
|
// now i want to append the label messages:
|
||||||
|
// - split the output by newlines
|
||||||
|
// - for every label, append a new line after each error
|
||||||
|
|
||||||
|
const lines = output.split("\n");
|
||||||
|
for (const label of error_labels) {
|
||||||
|
// get the line number of the label
|
||||||
|
const [line_number, col_number] = absolute_to_line_column(input, label.start);
|
||||||
|
const spaces = new Array(col_number - 1).fill(" ").join("");
|
||||||
|
lines.splice(line_number, 0, create_inline_error_message(spaces, label.message));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines.join("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
function create_inline_error_message(spaces: string, message: string): string {
|
||||||
|
return `<span class="relative inline-block w-full before:h-full before:block before:absolute before:left-0 before:w-[calc(100%+1.5rem)] before:-translate-x-3 before:bg-red-950 before:dark:bg-red-200" style="white-space: initial"><span class="relative text-red-200 dark:text-red-800">${spaces}╰╴${message}</span></span>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user