Skip to content

Conversation

@waywardmonkeys
Copy link
Contributor

…undary details

  • Replace ApplyAttributeError with Error { kind: ErrorKind, start, end, len, boundary }
  • AttributedText::apply_attribute now returns Result<(), Error>
  • Add Endpoint and BoundaryInfo (reports offending endpoint/index and enclosing codepoint span)
  • Enforce UTF-8 boundaries via TextStorage::is_char_boundary and surface detailed context
  • Enrich Display to include range, len, and boundary info
  • Re-export Error, ErrorKind, BoundaryInfo, Endpoint at crate root
  • Update tests to assert kinds and key details in messages

…undary details

- Replace `ApplyAttributeError` with `Error { kind: ErrorKind, start, end, len, boundary }`
- `AttributedText::apply_attribute` now returns Result<(), Error>
- Add `Endpoint` and `BoundaryInfo` (reports offending endpoint/index and enclosing codepoint span)
- Enforce UTF-8 boundaries via `TextStorage::is_char_boundary` and surface detailed context
- Enrich `Display` to include range, len, and boundary info
- Re-export `Error`, `ErrorKind`, `BoundaryInfo`, `Endpoint` at crate root
- Update tests to assert kinds and key details in messages
@waywardmonkeys waywardmonkeys force-pushed the attributed_text/error-context branch from 49fb329 to aeadccd Compare November 12, 2025 16:24
Copy link
Member

@tomcur tomcur left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good. Some nits inline, and perhaps the testing of the Display implementation in bad_range_for_apply_attribute should be snapshot-y, testing against the full output string we expect. Anyway, I've left some comments about the current asserts.

Comment on lines +197 to +199
if s == 0 {
break;
}
Copy link
Member

@tomcur tomcur Nov 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In principle this should be impossible, as text.is_char_boundary(0) should always be true.

Suggested change
if s == 0 {
break;
}
// We can never wrap around `0` here, as when `s == 0` before the decrement,
// the previous call to `text.is_char_boundary` (either in this loop or above)
// will have returned `true`.
debug_assert!(s != 0, "`s` should never wrap around 0").

assert_eq!(e.kind(), ErrorKind::InvalidRange);
let msg = format!("{}", e);
assert!(msg.contains("4..3"));
assert!(msg.contains("start > end") || msg.contains("invalid range"));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we expect to always keep saying both that the range is invalid, and why it's invalid?

Suggested change
assert!(msg.contains("start > end") || msg.contains("invalid range"));
assert!(msg.contains("start > end"));
assert!(msg.contains("invalid range"));

Err(e) => {
assert_eq!(e.kind(), ErrorKind::InvalidBounds);
let msg = format!("{}", e);
assert!(msg.contains("7..8") || msg.contains("8"));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to above, this perhaps should be &&, but at the same time, as written the second expression is implied by the first.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants