highlight code snippets better

This commit is contained in:
Folkert 2020-04-12 20:52:43 +02:00
parent c326b09964
commit 7632a4b484
11 changed files with 216 additions and 188 deletions

View file

@ -233,7 +233,7 @@ pub fn mono_problem<'b>(
alloc.string(index.ordinal()),
alloc.reflow(" pattern is redundant:"),
]),
alloc.region(branch_region),
alloc.region_with_subregion(overall_region, branch_region),
alloc.reflow(
"Any value of this shape will be handled by \
a previous pattern, so this one should be removed.",
@ -253,8 +253,6 @@ pub fn unhandled_patterns_to_doc_block<'b>(
alloc: &'b RocDocAllocator<'b>,
patterns: Vec<roc_mono::pattern::Pattern>,
) -> RocDocBuilder<'b> {
use roc_mono::pattern::Pattern::*;
alloc
.vcat(patterns.into_iter().map(|v| pattern_to_doc(alloc, v)))
.indent(4)
@ -726,33 +724,68 @@ impl<'a> RocDocAllocator<'a> {
.annotate(Annotation::Hint)
}
pub fn region(&'a self, region: roc_region::all::Region) -> DocBuilder<'a, Self, Annotation> {
pub fn region_with_subregion(
&'a self,
region: roc_region::all::Region,
sub_region: roc_region::all::Region,
) -> DocBuilder<'a, Self, Annotation> {
debug_assert!(region.contains(&sub_region));
// if true, the final line of the snippet will be some ^^^ that point to the region where
// the problem is. Otherwise, the snippet will have a > on the lines that are in the regon
// where the problem is.
let error_highlight_line = sub_region.start_line == region.end_line;
let max_line_number_length = (region.end_line + 1).to_string().len();
let indent = 2;
if region.start_line == region.end_line {
let i = region.start_line;
let mut result = self.nil();
for i in region.start_line..=region.end_line {
let line_number_string = (i + 1).to_string();
let line_number = line_number_string;
let this_line_number_length = line_number.len();
let line = self.src_lines[i as usize];
let rest_of_line = if line.trim().is_empty() {
self.nil()
let rest_of_line = if !line.trim().is_empty() {
self.text(line)
.annotate(Annotation::CodeBlock)
.indent(indent)
} else {
self.nil()
.append(self.text(line).indent(2))
.annotate(Annotation::CodeBlock)
};
let source_line = self
.text(" ".repeat(max_line_number_length - this_line_number_length))
.append(self.text(line_number).annotate(Annotation::LineNumber))
.append(self.text("").annotate(Annotation::GutterBar))
.append(rest_of_line);
let source_line = if !error_highlight_line
&& i >= sub_region.start_line
&& i <= sub_region.end_line
{
self.text(" ".repeat(max_line_number_length - this_line_number_length))
.append(self.text(line_number).annotate(Annotation::LineNumber))
.append(self.text("").annotate(Annotation::GutterBar))
.append(self.text(">").annotate(Annotation::Error))
.append(rest_of_line)
} else if error_highlight_line {
self.text(" ".repeat(max_line_number_length - this_line_number_length))
.append(self.text(line_number).annotate(Annotation::LineNumber))
.append(self.text("").annotate(Annotation::GutterBar))
.append(rest_of_line)
} else {
self.text(" ".repeat(max_line_number_length - this_line_number_length))
.append(self.text(line_number).annotate(Annotation::LineNumber))
.append(self.text("").annotate(Annotation::GutterBar))
.append(self.text(" "))
.append(rest_of_line)
};
let highlight_text = "^".repeat((region.end_col - region.start_col) as usize);
result = result.append(source_line);
if i != region.end_line {
result = result.append(self.line())
}
}
if error_highlight_line {
let highlight_text = "^".repeat((sub_region.end_col - sub_region.start_col) as usize);
let highlight_line = self
.line()
.append(self.text(" ".repeat(max_line_number_length)))
@ -760,44 +793,19 @@ impl<'a> RocDocAllocator<'a> {
.append(if highlight_text.is_empty() {
self.nil()
} else {
self.text(" ".repeat(region.start_col as usize))
self.text(" ".repeat(sub_region.start_col as usize))
.indent(indent)
.append(self.text(highlight_text).annotate(Annotation::Error))
});
source_line.append(highlight_line)
} else {
let mut result = self.nil();
for i in region.start_line..=region.end_line {
let line_number_string = (i + 1).to_string();
let line_number = line_number_string;
let this_line_number_length = line_number.len();
let line = self.src_lines[i as usize];
let rest_of_line = if !line.trim().is_empty() {
self.text(line)
.annotate(Annotation::CodeBlock)
.indent(indent)
} else {
self.nil()
};
let source_line = self
.text(" ".repeat(max_line_number_length - this_line_number_length))
.append(self.text(line_number).annotate(Annotation::LineNumber))
.append(self.text("").annotate(Annotation::GutterBar))
.append(self.text(">").annotate(Annotation::Error))
.append(rest_of_line);
result = result.append(source_line);
if i != region.end_line {
result = result.append(self.line())
}
}
result
result = result.append(highlight_line);
}
result
}
pub fn region(&'a self, region: roc_region::all::Region) -> DocBuilder<'a, Self, Annotation> {
self.region_with_subregion(region, region)
}
pub fn ident(&'a self, ident: Ident) -> DocBuilder<'a, Self, Annotation> {

View file

@ -40,15 +40,20 @@ fn report_mismatch<'b>(
found: ErrorType,
expected_type: ErrorType,
region: roc_region::all::Region,
_opt_highlight: Option<roc_region::all::Region>,
opt_highlight: Option<roc_region::all::Region>,
problem: RocDocBuilder<'b>,
this_is: RocDocBuilder<'b>,
instead_of: RocDocBuilder<'b>,
further_details: Option<RocDocBuilder<'b>>,
) -> Report<'b> {
let snippet = if let Some(highlight) = opt_highlight {
alloc.region_with_subregion(highlight, region)
} else {
alloc.region(region)
};
let lines = vec![
problem,
alloc.region(region),
snippet,
type_comparison(
alloc,
found,
@ -74,14 +79,19 @@ fn report_bad_type<'b>(
found: ErrorType,
expected_type: ErrorType,
region: roc_region::all::Region,
_opt_highlight: Option<roc_region::all::Region>,
opt_highlight: Option<roc_region::all::Region>,
problem: RocDocBuilder<'b>,
this_is: RocDocBuilder<'b>,
further_details: RocDocBuilder<'b>,
) -> Report<'b> {
let snippet = if let Some(highlight) = opt_highlight {
alloc.region_with_subregion(highlight, region)
} else {
alloc.region(region)
};
let lines = vec![
problem,
alloc.region(region),
snippet,
lone_type(
alloc,
found,
@ -150,6 +160,8 @@ fn to_expr_report<'b>(
None => (alloc.text("this"), alloc.nil()),
};
let mut region = None;
let thing = match annotation_source {
TypedIfBranch {
index,
@ -176,17 +188,20 @@ fn to_expr_report<'b>(
alloc.keyword("when"),
alloc.text(" expression:"),
]),
TypedBody => alloc.concat(vec![
alloc.text("body of "),
the_name_text,
alloc.text(" definition:"),
]),
TypedBody { region: ann_region } => {
region = Some(ann_region);
alloc.concat(vec![
alloc.text("body of "),
the_name_text,
alloc.text(" definition:"),
])
}
};
let it_is = match annotation_source {
TypedIfBranch { index, .. } => format!("The {} branch is", index.ordinal()),
TypedWhenBranch { index, .. } => format!("The {} branch is", index.ordinal()),
TypedBody => "The body is".into(),
TypedBody { .. } => "The body is".into(),
};
let comparison = type_comparison(
@ -207,7 +222,14 @@ fn to_expr_report<'b>(
filename,
doc: alloc.stack(vec![
alloc.text("Something is off with the ").append(thing),
alloc.region(expr_region),
match region {
None => alloc.region(expr_region),
Some(ann_region) => {
let joined =
roc_region::all::Region::span_across(&ann_region, &expr_region);
alloc.region_with_subregion(joined, expr_region)
}
},
comparison,
]),
}