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

Allow TextArea API edits to defer batching #4428

Open
tconbeer opened this issue Apr 18, 2024 · 3 comments
Open

Allow TextArea API edits to defer batching #4428

tconbeer opened this issue Apr 18, 2024 · 3 comments

Comments

@tconbeer
Copy link
Contributor

tconbeer commented Apr 18, 2024

Right now the TextArea's undo behavior is defined by a set of heuristics to determine whether or not edits should be batched together:

A new batch/checkpoint is created when:
- The undo stack is empty.
- The checkpoint timer expires.
- The maximum number of characters permitted in a checkpoint is reached.
- A redo is performed (we should not add new edits to a batch that has been redone).
- The programmer has requested a new batch via a call to `force_new_batch`.
- e.g. the TextArea widget may call this method in some circumstances.
- Clicking to move the cursor elsewhere in the document should create a new batch.
- Movement of the cursor via a keyboard action that is NOT an edit.
- Blurring the TextArea creates a new checkpoint.
- The current edit involves a deletion/replacement and the previous edit did not.
- The current edit is a pure insertion and the previous edit was not.
- The edit involves insertion or deletion of one or more newline characters.
- An edit which inserts more than a single character (a paste) gets an isolated batch.

There is an API to force a new batch, but not the opposite: I would like to be able to batch edits together into a single undo.

For example, in Harlequin, I support ctrl+/ to toggle a comment marker at the start of each selected line. I currently achieve this by looping over the selected lines and calling TextArea.insert() or TextArea.delete().

Deleting comments currently works as expected - a user presses ctrl+/ to delete comments, and they can undo that delete action with a single ctrl+z.

However, inserting comments doesn't work as well. Since I'm inserting more than one character (the comment marker(s) and a single space), TextArea creates an undo batch for each line that is edited. Pressing ctrl+z undoes a single line's comments at a time. Counter-intuitively, if I break these inserts into a single character (to hack the current heuristic), I can get the behavior I want (mostly, as long as I'm inserting fewer than 100 characters).

I'd prefer an API to defer undo batching. That could be via a kwarg on TextArea.insert() (and other methods) or by one or more calls to TextArea.history (an EditHistory), like TextArea.history.defer_batching() followed by TextArea.history.checkpoint(). Or as a context manager:

class MyTextArea(TextArea):
    def action_toggle_comments(self) -> None:
        ...
        with self.history.defer_batching():
            for line in lines:
                self.insert(...)
Copy link

Thank you for your issue. Give us a little time to review it.

PS. You might want to check the FAQ if you haven't done so already.

This is an automated reply, generated by FAQtory

@darrenburns
Copy link
Member

Good idea 👍

With the approach you suggested, I'm unsure what happens after the context manager exits - does it immediately put everything within into its own batch, or does it wait until the heuristic triggers a new batch?

I wonder if a context manager called batch which groups everything within the context into a single batch would work?

@tconbeer
Copy link
Contributor Author

Yeah, I was thinking it would create a batch on exit. Kind of like begin/commit for database libs.

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

No branches or pull requests

2 participants