v / vlib / v2 / errors / details.v
44 lines · 42 sloc · 1.35 KB · 09cc0c5133d075ee6dcff29286dce7eb7d4421da
Raw
1module errors
2
3import os
4import v2.token
5
6// loads the source file and generates the error message including the source
7// line and column. offending token is highlighted in the snipped of source code.
8// since this is used on errors, loading the source file isnt an issue.
9// TODO: probably needs a better name
10pub fn details(file &token.File, pos token.Position, row_padding int) string {
11 if file.name == '' {
12 return 'at ${pos.line}:${pos.column}'
13 }
14 src := os.read_file(file.name) or { return 'at ${pos.line}:${pos.column} in `${file.name}`' }
15 line_start := if pos.line - row_padding - 1 > 0 {
16 file.line_start(pos.line - row_padding)
17 } else {
18 0
19 }
20 mut line_end := pos.offset + 1
21 for i := 0; line_end < src.len; {
22 if src[line_end] == `\n` {
23 i++
24 if i == row_padding + 1 {
25 break
26 }
27 }
28 line_end++
29 }
30 lines_src := src[line_start..line_end].split('\n')
31 line_no_start, _ := file.find_line_and_column(line_start)
32 mut lines_src_formatted := []string{}
33 for i in 0 .. lines_src.len {
34 line_no := line_no_start + i
35 line_src := lines_src[i]
36 line_spaces := line_src.replace('\t', ' ')
37 lines_src_formatted << '${line_no:5d} | ' + line_spaces
38 if line_no == pos.line {
39 space_diff := line_spaces.len - line_src.len
40 lines_src_formatted << ' ' + ' '.repeat(space_diff + pos.column - 1) + '^'
41 }
42 }
43 return lines_src_formatted.join('\n')
44}
45