Skip to content
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

[SuperTextField] - Create a controller that supports undo/redo (Resolves #189) #704

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

matthew-carroll
Copy link
Contributor

[SuperTextField] - Create a controller that supports undo/redo.

This PR creates an EventSourcedAttributedTextEditingValue, which holds text, a selection, and a composing region, along with a history of commands that were run to produce the current value. The value can undo() and redo() those commands.

The commands are based on an interface called AttributedTextEditingValueCommand.

I ported the existing AttributedTextEditingController interface over to a new one called EventSourcedAttributedTextEditingController. I implemented the interface using the new event sourced value and a group of new commands. I also wrote tests for nearly every operation in the controller, and their ability to undo an operation.

Some things that are not addressed in this PR:

  • How do we handle composing attributions as things are undone and redone?
  • How can a developer add new pieces of information to the history, given that all commands operate on a type-safe data structure?
  • How can developers optionally batch commands in retrospect so that, e.g., similar commands in quick succession are batched and undone together.

@matthew-carroll matthew-carroll changed the title [SuperTextField] - Create a controller that supports undo/redo [SuperTextField] - Create a controller that supports undo/redo (Resolves #189) Jul 16, 2022
@matthew-carroll
Copy link
Contributor Author

@venkatd - would you like to give this PR a try in your app and see if this undo/redo works for you?

@venkatd
Copy link

venkatd commented Jul 17, 2022

Hi @matthew-carroll I really like the direction of this. We would want the ability to compose/group actions in order to replace our internal implementation. Having commands produce edits (or changes/events depending on ones preference) gives us undo and grouping for free in many cases.

If your time allows a quick call this month could let us compare notes on the approach and how we might be able to drop our hand-rolled undo/redo.

How can a developer add new pieces of information to the history, given that all commands operate on a type-safe data structure?

Could you give an example of what you mean by this?

Copy link
Collaborator

@angelosilvestre angelosilvestre left a comment

Choose a reason for hiding this comment

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

LGTM with a few comments


group("deletes text", () {
test("between the caret and the beginning of the line", () {
// TODO:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should these tests be implemented in this PR?

});

test("pastes text from clipboard", () {
// TODO:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should this test be implemented in this PR?

_previousComposingRange = previousValue.composingRegion;

return AttributedTextEditingValue(
text: previousValue.text,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Shouldn't the text be copied here like in the other methods?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think it matters because we're not changing the text, but I see that I copied the text in the "select all" command, so I'll add a copy() here, too.

Comment on lines 266 to 273
extension on AttributedText {
AttributedText copy() {
return AttributedText(
text: text,
spans: spans.copy(),
);
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Wouldn't it be better if this extension was placed after all the commands instead of being placed between two commands?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, I'll move it down.

@matthew-carroll
Copy link
Contributor Author

@venkatd it sounds like what you need is the ability for a command to look at recent history and re-group them, right?

In terms of what's introduced in this PR, are there any API decisions here that you think would prevent adoption of this approach? Should we merge in and then expand the behavior, or do you think we need to revisit what's here so far?

@matthew-carroll
Copy link
Contributor Author

@angelosilvestre - I updated the PR for your comments. I implemented one of those empty tests and deleted the other two.

I also found a bug in the Markdown serialization. It was breaking on a single-character styles. I wrote a test suite and re-organized the code.

@matthew-carroll
Copy link
Contributor Author

FYI - I extracted the markdown serialization fixes from this PR and merged them separately. So now they've disappeared from this PR's file changes.

@miguelcmedeiros miguelcmedeiros removed their request for review May 22, 2024 17:04
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.

3 participants