mirror of https://github.com/astral-sh/ruff
[ty_test] Calculate hover column at parse time
Move the column calculation from generate_hover_outputs to the HoverAssertion parsing logic. This makes better use of the existing column field in HoverAssertion. Changes: - UnparsedAssertion::Hover now stores both the expected type and the full comment text - HoverAssertion::from_str() now takes both parameters and calculates the column from the down arrow position in the full comment - generate_hover_outputs() now reads the column from the parsed assertion instead of recalculating it This eliminates redundant calculations and makes the column field actually useful. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
0198857224
commit
51d5bc709d
|
|
@ -246,23 +246,26 @@ pub(crate) enum UnparsedAssertion<'a> {
|
|||
/// An `# error:` assertion.
|
||||
Error(&'a str),
|
||||
|
||||
/// A `# hover:` assertion, with the full comment text including the down arrow.
|
||||
Hover(&'a str),
|
||||
/// A `# hover:` assertion.
|
||||
///
|
||||
/// The first string is the expected type (body after `hover:`).
|
||||
/// The second string is the full comment text (including the down arrow).
|
||||
Hover(&'a str, &'a str),
|
||||
}
|
||||
|
||||
impl<'a> UnparsedAssertion<'a> {
|
||||
/// Returns `Some(_)` if the comment starts with `# error:`, `# revealed:`, or `# hover:`,
|
||||
/// indicating that it is an assertion comment.
|
||||
fn from_comment(comment: &'a str) -> Option<Self> {
|
||||
let comment = comment.trim().strip_prefix('#')?.trim();
|
||||
let (keyword, body) = comment.split_once(':')?;
|
||||
let trimmed = comment.trim().strip_prefix('#')?.trim();
|
||||
let (keyword, body) = trimmed.split_once(':')?;
|
||||
let keyword = keyword.trim();
|
||||
let body = body.trim();
|
||||
|
||||
match keyword {
|
||||
"revealed" => Some(Self::Revealed(body)),
|
||||
"error" => Some(Self::Error(body)),
|
||||
"hover" | "↓ hover" => Some(Self::Hover(body)),
|
||||
"hover" | "↓ hover" => Some(Self::Hover(body, comment)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
@ -280,9 +283,11 @@ impl<'a> UnparsedAssertion<'a> {
|
|||
Self::Error(error) => ErrorAssertion::from_str(error)
|
||||
.map(ParsedAssertion::Error)
|
||||
.map_err(PragmaParseError::ErrorAssertionParseError),
|
||||
Self::Hover(hover) => HoverAssertion::from_str(hover)
|
||||
.map(ParsedAssertion::Hover)
|
||||
.map_err(PragmaParseError::HoverAssertionParseError),
|
||||
Self::Hover(expected_type, full_comment) => {
|
||||
HoverAssertion::from_str(expected_type, full_comment)
|
||||
.map(ParsedAssertion::Hover)
|
||||
.map_err(PragmaParseError::HoverAssertionParseError)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -292,7 +297,7 @@ impl std::fmt::Display for UnparsedAssertion<'_> {
|
|||
match self {
|
||||
Self::Revealed(expected_type) => write!(f, "revealed: {expected_type}"),
|
||||
Self::Error(assertion) => write!(f, "error: {assertion}"),
|
||||
Self::Hover(expected_type) => write!(f, "hover: {expected_type}"),
|
||||
Self::Hover(expected_type, _) => write!(f, "hover: {expected_type}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -367,16 +372,25 @@ pub(crate) struct HoverAssertion<'a> {
|
|||
}
|
||||
|
||||
impl<'a> HoverAssertion<'a> {
|
||||
fn from_str(source: &'a str) -> Result<Self, HoverAssertionParseError> {
|
||||
if source.is_empty() {
|
||||
fn from_str(
|
||||
expected_type: &'a str,
|
||||
full_comment: &'a str,
|
||||
) -> Result<Self, HoverAssertionParseError> {
|
||||
if expected_type.is_empty() {
|
||||
return Err(HoverAssertionParseError::EmptyType);
|
||||
}
|
||||
|
||||
// Column will be computed from the comment position in the matcher
|
||||
// For now, we just validate and store the expected type
|
||||
// Find the down arrow position in the full comment to determine the column
|
||||
let arrow_position = full_comment
|
||||
.find('↓')
|
||||
.ok_or(HoverAssertionParseError::MissingDownArrow)?;
|
||||
|
||||
// Column is 1-indexed, and the arrow position is 0-indexed
|
||||
let column = OneIndexed::from_zero_indexed(arrow_position);
|
||||
|
||||
Ok(Self {
|
||||
column: OneIndexed::from_zero_indexed(0), // Placeholder, will be set by matcher
|
||||
expected_type: source,
|
||||
column,
|
||||
expected_type,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,21 +95,23 @@ pub(crate) fn generate_hover_outputs(
|
|||
|
||||
// Look for hover assertions in this line's assertions
|
||||
for assertion in line_assertions.iter() {
|
||||
let crate::assertion::UnparsedAssertion::Hover(hover_text) = assertion else {
|
||||
let crate::assertion::UnparsedAssertion::Hover(_, _) = assertion else {
|
||||
continue;
|
||||
};
|
||||
|
||||
// Find the down arrow position in the comment text to determine the column
|
||||
let Some(arrow_position) = hover_text.find('↓') else {
|
||||
// No down arrow - skip this hover assertion (will be caught as error by matcher)
|
||||
// Parse the assertion to get the column
|
||||
let Ok(crate::assertion::ParsedAssertion::Hover(hover)) = assertion.parse() else {
|
||||
// Invalid hover assertion - will be caught as error by matcher
|
||||
continue;
|
||||
};
|
||||
|
||||
// Get the start offset of the target line
|
||||
let target_line_start = lines.line_start(target_line, &source);
|
||||
|
||||
// Calculate the hover position: start of target line + arrow column (0-indexed)
|
||||
let hover_offset = target_line_start + TextSize::try_from(arrow_position).unwrap();
|
||||
// Calculate the hover position from the column in the parsed assertion
|
||||
// Column is 1-indexed, so convert to 0-indexed for TextSize
|
||||
let hover_offset =
|
||||
target_line_start + TextSize::try_from(hover.column.get() - 1).unwrap();
|
||||
|
||||
// Get the inferred type at that position
|
||||
let Some(inferred_type) = infer_type_at_position(db, file, hover_offset) else {
|
||||
|
|
|
|||
Loading…
Reference in New Issue