Skip to content

fixed issue #159933 #172546

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open

fixed issue #159933 #172546

wants to merge 3 commits into from

Conversation

a5xwin
Copy link

@a5xwin a5xwin commented Jul 22, 2025

Fix TextSpan getSpanForPositionVisitor to properly handle WidgetSpan positioning

This PR fixes an issue where TextSpan.getSpanForPositionVisitor was not properly returning WidgetSpan instances at the correct positions. The previous implementation had logic errors in handling text affinity and position calculations, causing WidgetSpan elements to be incorrectly skipped or not found.

Changes made:

  • TextSpan: Improved the getSpanForPositionVisitor method to properly respect upstream affinity and handle position ranges correctly
  • WidgetSpan: Enhanced the position visitor logic to accurately detect when the cursor is within the widget span boundaries
  • Added proper bounds checking and affinity handling for both downstream and upstream text positions

Testing:

  • Ran multiple test cases using custom generated scenarios
  • All tests now correctly return WidgetSpan instances at their expected positions
  • Existing functionality for TextSpan positioning remains unchanged

Fixes #159933

Pre-launch Checklist

Note: CLA will be signed when prompted by the bot after PR submission.

If you need help, consider asking for advice on the #hackers-new channel on Discord.

@flutter-dashboard
Copy link

It looks like this pull request may not have tests. Please make sure to add tests or get an explicit test exemption before merging.

If you are not sure if you need tests, consider this rule of thumb: the purpose of a test is to make sure someone doesn't accidentally revert the fix. Ask yourself, is there anything in your PR that you feel it is important we not accidentally revert back to how it was before your fix?

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.If you believe this PR qualifies for a test exemption, contact "@test-exemption-reviewer" in the #hackers channel in Discord (don't just cc them here, they won't see it!). The test exemption team is a small volunteer group, so all reviewers should feel empowered to ask for tests, without delegating that responsibility entirely to the test exemption group.

Copy link

google-cla bot commented Jul 22, 2025

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@github-actions github-actions bot added a: text input Entering text in a text field or keyboard related problems framework flutter/packages/flutter repository. See also f: labels. labels Jul 22, 2025
@justinmc
Copy link
Contributor

@Renzo-Olivares From your work on rich text does it seem like this is a valid correction of getSpanForPositionVisitor?

@Renzo-Olivares Renzo-Olivares self-requested a review July 22, 2025 22:34
InlineSpan? getSpanForPositionVisitor(TextPosition position, Accumulator offset) {
if (position.offset == offset.value) {
// Record where this WidgetSpan begins in the flat text.
Copy link
Contributor

Choose a reason for hiding this comment

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

Good catch, it looks like WidgetSpan.getSpanForPositionVisitor did not handle the upstream affinity case.

// Record where this WidgetSpan begins in the flat text.
final int start = offset.value;
// Advance past this one “placeholder” code unit.
offset.increment(1);
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this increment can remain in its original place (above the last null in this method).

Comment on lines +207 to +208


Copy link
Contributor

Choose a reason for hiding this comment

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

nit: these new lines look unintentional, if so let's remove them.

return null;
@override
InlineSpan? getSpanForPositionVisitor(TextPosition position, Accumulator offset) {
final int currentOffset = offset.value;
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure the changes in this method are necessary (the issue seems to be fixed with only the WidgetSpan changes). Can you explain what cases the changes in this code are trying to solve?

@Renzo-Olivares
Copy link
Contributor

Renzo-Olivares commented Jul 23, 2025

Hi @a5xwin, thank you for the contribution! I left a few comments.

The failing Linux analyze test should clear up once you run dart format on the files you modified.

This change will also need a test, maybe we can add it to text_span_test.dart, for example (should use getSpanForPositionVisitor instead):

test('GetSpanForPosition with WidgetSpan', () {
  const TextSpan textSpan = TextSpan(
    text: 'a',
    children: <InlineSpan>[
      TextSpan(text: 'b'),
      WidgetSpan(
        child: Text.rich(
          TextSpan(
            children: <InlineSpan>[
              WidgetSpan(child: SizedBox(width: 10, height: 10)),
              TextSpan(text: 'The sky is falling :)'),
            ],
          ),
        ),
      ),
      TextSpan(text: 'c'),
    ],
  );

  expect(textSpan.getSpanForPosition(const TextPosition(offset: 0)).runtimeType, TextSpan);
  expect(textSpan.getSpanForPosition(const TextPosition(offset: 1)).runtimeType, TextSpan);
  expect(textSpan.getSpanForPosition(const TextPosition(offset: 2)).runtimeType, WidgetSpan);
  expect(textSpan.getSpanForPosition(const TextPosition(offset: 3)).runtimeType, TextSpan);
});

Copy link
Contributor

@victorsanni victorsanni left a comment

Choose a reason for hiding this comment

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

Hi @a5xwin, could you run dart format to correctly format all the files in this PR? And also add tests to prevent regressing these changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
a: text input Entering text in a text field or keyboard related problems framework flutter/packages/flutter repository. See also f: labels.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

TextSpan doesn't return WidgetSpan at position
4 participants
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy