Add hint when string is used in place of label (#4330)

This commit is contained in:
+merlan #flirora 2024-06-11 05:08:30 -04:00 committed by GitHub
parent 7fa86eed0e
commit 20475ab0bf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 50 additions and 16 deletions

View File

@ -408,7 +408,7 @@ impl Lexer<'_> {
}
fn ref_marker(&mut self) -> SyntaxKind {
self.s.eat_while(|c| is_id_continue(c) || matches!(c, ':' | '.'));
self.s.eat_while(is_valid_in_label_literal);
// Don't include the trailing characters likely to be part of text.
while matches!(self.s.scout(-1), Some('.' | ':')) {
@ -419,7 +419,7 @@ impl Lexer<'_> {
}
fn label(&mut self) -> SyntaxKind {
let label = self.s.eat_while(|c| is_id_continue(c) || matches!(c, ':' | '.'));
let label = self.s.eat_while(is_valid_in_label_literal);
if label.is_empty() {
return self.error("label cannot be empty");
}
@ -918,3 +918,14 @@ fn is_math_id_start(c: char) -> bool {
fn is_math_id_continue(c: char) -> bool {
is_xid_continue(c) && c != '_'
}
/// Whether a character can be part of a label literal's name.
#[inline]
fn is_valid_in_label_literal(c: char) -> bool {
is_id_continue(c) || matches!(c, ':' | '.')
}
/// Returns true if this string is valid in a label literal.
pub fn is_valid_label_literal_id(id: &str) -> bool {
!id.is_empty() && id.chars().all(is_valid_in_label_literal)
}

View File

@ -19,7 +19,8 @@ pub use self::file::FileId;
pub use self::highlight::{highlight, highlight_html, Tag};
pub use self::kind::SyntaxKind;
pub use self::lexer::{
is_id_continue, is_id_start, is_ident, is_newline, link_prefix, split_newlines,
is_id_continue, is_id_start, is_ident, is_newline, is_valid_label_literal_id,
link_prefix, split_newlines,
};
pub use self::node::{LinkedChildren, LinkedNode, Side, SyntaxError, SyntaxNode};
pub use self::parser::{parse, parse_code, parse_math};

View File

@ -3,7 +3,7 @@ use std::fmt::Write;
use std::hash::Hash;
use std::ops::Add;
use ecow::{eco_format, EcoString};
use ecow::eco_format;
use smallvec::SmallVec;
use unicode_math_class::MathClass;
@ -42,7 +42,7 @@ pub trait Reflect {
/// dynamic checks instead of optimized machine code for each type).
fn castable(value: &Value) -> bool;
/// Produce an error message for an inacceptable value type.
/// Produce an error message for an unacceptable value type.
///
/// ```ignore
/// assert_eq!(
@ -51,7 +51,7 @@ pub trait Reflect {
/// );
/// ```
fn error(found: &Value) -> HintedString {
Self::input().error(found).into()
Self::input().error(found)
}
}
@ -300,7 +300,7 @@ pub enum CastInfo {
impl CastInfo {
/// Produce an error message describing what was expected and what was
/// found.
pub fn error(&self, found: &Value) -> EcoString {
pub fn error(&self, found: &Value) -> HintedString {
let mut matching_type = false;
let mut parts = vec![];
@ -328,13 +328,26 @@ impl CastInfo {
write!(msg, "{}", found.ty()).unwrap();
}
let mut msg: HintedString = msg.into();
if let Value::Int(i) = found {
if parts.iter().any(|p| p == "length") && !matching_type {
write!(msg, ": a length needs a unit - did you mean {i}pt?").unwrap();
if !matching_type && parts.iter().any(|p| p == "length") {
msg.hint(eco_format!("a length needs a unit - did you mean {i}pt?"));
}
} else if let Value::Str(s) = found {
if !matching_type && parts.iter().any(|p| p == "label") {
if typst_syntax::is_valid_label_literal_id(s) {
msg.hint(eco_format!(
"use `<{s}>` or `label({})` to create a label",
s.repr()
));
} else {
msg.hint(eco_format!("use `label({})` to create a label", s.repr()));
}
}
}
msg.into()
msg
}
/// Walk all contained non-union infos.

View File

@ -610,11 +610,7 @@ macro_rules! primitive {
match value {
Value::$variant(v) => Ok(v),
$(Value::$other$(($binding))? => Ok($out),)*
v => Err(eco_format!(
"expected {}, found {}",
Type::of::<Self>(),
v.ty(),
).into()),
v => Err(<Self as Reflect>::error(&v)),
}
}
}

View File

@ -45,7 +45,8 @@
}
--- length-unit-hint ---
// Error: 1:17-1:19 expected length, found integer: a length needs a unit - did you mean 12pt?
// Error: 17-19 expected length, found integer
// Hint: 17-19 a length needs a unit - did you mean 12pt?
#set text(size: 12)
--- length-ignore-em-pt-hint ---

View File

@ -114,3 +114,15 @@ B #cite(<netwok>) #cite(<arrgh>).
@mcintosh_anxiety
#show bibliography: none
#bibliography("/assets/bib/works.bib", style: "chicago-author-date")
--- cite-type-error-hint ---
// Test hint for cast error from str to label
// Error: 7-15 expected label, found string
// Hint: 7-15 use `<netwok>` or `label("netwok")` to create a label
#cite("netwok")
--- cite-type-error-hint-invalid-literal ---
// Test hint for cast error from str to label
// Error: 7-17 expected label, found string
// Hint: 7-17 use `label("%@&#*!\\")` to create a label
#cite("%@&#*!\\")