Go Back   Cockos Incorporated Forums > REAPER Forums > REAPER Feature Requests

Reply
 
Thread Tools Display Modes
Old 07-15-2018, 07:35 PM   #1
Lokasenna
Human being with feelings
 
Lokasenna's Avatar
 
Join Date: Sep 2008
Location: Calgary, AB, Canada
Posts: 6,551
Default API: Allow the undo block functions to work with coroutines

I've got a script doing some heavy processing that would freeze Reaper for a minute or two. Figured I'd get off my ass and learn how to use coroutines, which are working beautifully and proved much easier than I expected.

However, doing so breaks the Undo_BeginBlock / Undo_EndBlock pair - understandably - so my entry in Undo History is just "Reascript: Run...".

Any chance these could play nicely together? I can see why it might be awkward to do - my suggestion would be:

- Add a flag to BeginBlock, or a separate function call, designating it as an undo block that will span multiple script loops.

- Add ContinueBlock, to call when the coroutine pauses and let Reaper know we're still working on this undo block. Equivalent to gfx.update for maintaining a window.

- EndBlock continues doing its thing.

I can see this creating an awkward period for the Undo History while the processing is going on, or if the script was aborted prematurely. Perhaps we could provide a string for the undo display beforehand, with the understanding that everything until the EndBlock statement would be compiled into that one entry.

Cheers.
__________________
I'm no longer using Reaper or working on scripts for it. Sorry. :(
Default 5.0 Nitpicky Edition / GUI library for Lua scripts / Theory Helper / Radial Menu / Donate
Lokasenna is offline   Reply With Quote
Old 07-18-2018, 08:34 AM   #2
juliansader
Human being with feelings
 
Join Date: Jul 2009
Posts: 3,714
Default

This sounds very interesting! What are the advantages of using coroutines in REAPER scripts?


P.S. The same undo problem also affects deferred scripts.
juliansader is offline   Reply With Quote
Old 07-18-2018, 08:39 AM   #3
deeb
Human being with feelings
 
deeb's Avatar
 
Join Date: Feb 2017
Posts: 4,820
Default

Quote:
Originally Posted by juliansader View Post
This sounds very interesting! What are the advantages of using coroutines in REAPER scripts?


P.S. The same undo problem also affects deferred scripts.
i wondered the same! i don't see many benefits in practice in reaper world tho. But i don't know.
deeb is online now   Reply With Quote
Old 07-18-2018, 09:01 AM   #4
Lokasenna
Human being with feelings
 
Lokasenna's Avatar
 
Join Date: Sep 2008
Location: Calgary, AB, Canada
Posts: 6,551
Default

Scripts doing a lot of processing (do X to 3000 items) can use coroutines to pause, let Reaper update, and then continue from where they were on the next script loop so Reaper doesn't just freeze up for 2 minutes.

The same functionality is doable without coroutines, by having a function count how many loops have been run, defer, and then call that function again to start at the next index, but using coroutines is much simpler and doesn't require rearranging your defer logic to accomodate them.

Code:
-- Create a coroutine and return a function that will run it
-- See coroutine.create, coroutine.resume, and coroutine.status for more complicated structures
local Loop = coroutine.wrap( function()
    for i = 1, 1000 do

        -- Pause this function exactly where it is until called again
        -- Arguments passed to yield are returned by the coroutine function, below.
        coroutine.yield(i)

    end
end)

gfx.init("Coroutine test", 256, 128, 0, 96, 96)
local function Main()

    local char = gfx.getchar()
    if char == -1 or char == 27 then
        return
    end


    -- Start the coroutine, or resume from where it was paused
    -- Returns the value passed to coroutine.yield, above.
    local val = Loop()

    if val then

        gfx.x, gfx.y = 16, 16
        gfx.drawstr("current count: " .. tostring(val))

        reaper.defer(Main)
        gfx.update()

    end

end

Main()
__________________
I'm no longer using Reaper or working on scripts for it. Sorry. :(
Default 5.0 Nitpicky Edition / GUI library for Lua scripts / Theory Helper / Radial Menu / Donate

Last edited by Lokasenna; 07-18-2018 at 09:11 AM.
Lokasenna is offline   Reply With Quote
Old 07-18-2018, 09:32 AM   #5
deeb
Human being with feelings
 
deeb's Avatar
 
Join Date: Feb 2017
Posts: 4,820
Default

it hads value! : ) hope devs consider this
deeb is online now   Reply With Quote
Old 07-20-2018, 05:50 AM   #6
Meo-Ada Mespotine
Human being with feelings
 
Meo-Ada Mespotine's Avatar
 
Join Date: May 2017
Location: Leipzig
Posts: 6,629
Default

Wohooo...that's cool
Meo-Ada Mespotine is online now   Reply With Quote
Old 08-05-2020, 05:20 PM   #7
jkooks
Human being with feelings
 
Join Date: May 2020
Posts: 190
Default

Anyone know if there is a way to fix these undo block issues yet? Particularly with defer?

I'm using defer to loop through a function and figured I would call Undo_BeginBlock the first iteration and then Undo_EndBlock on the last, but that hasn't worked out as well as I wanted it to (doesn't seem like the EndBlock is creating a new point and leaves it as a "ReaScript: Run" entry).


(And if this issue isn't fixed, then +1 for Lokasenna's original request!)
jkooks is offline   Reply With Quote
Old 08-06-2020, 03:00 PM   #8
Meo-Ada Mespotine
Human being with feelings
 
Meo-Ada Mespotine's Avatar
 
Join Date: May 2017
Location: Leipzig
Posts: 6,629
Default

It's actually complicated on a design level.
Assume, you have a deferred script running, creating an undopoint over its lifetime.
During that time, other actions create undo points as well.
Now you have the problem that the other undopoint is in "the middle" of the defer undopoint.

So it could look something like this:

Defer undopoint
Other action undopoint
Defer undopoint continuation.

In which order do you want them to be undone?
Other action and then both Defer undopoints, as defer was started first?

Defer undopoints first, as they were the last one created and finished?

Defer continuation, then other Action then Defer, so defer has multiple undopoints?
The latter would be the most logical but that means, that you can create only one undopoint per defer-cycle, which can flood the undolist. And sometimes you want the changes of multiple defer-cycles consolidated into one undopoint but this wouldn't be possible that way.


And I haven't even started, that the undo states have a chronology. If you consolidate numerous undo from multiple defer-cycles from your deferscript, undoing it can create havoc with things added/changed by actions not part of your deferscript. In short, you have consistency issues.

It's more complicated than it appears in the end, if the do/undo/redo behavior shall be logical and predictable.
You don't want a project ruined, just because a defer-script messed up the chronology of the undostates.

Multiple paths could be an option. But the number of possible undo paths explodes quickly, including your head that tries to wrap itself around it.

It's complicated and probably only doable with setbacks and compromises.
__________________
Use you/she/her.Ultraschall-Api Lua Api4Reaper - Donate, if you wish

On vacation for the time being...
Meo-Ada Mespotine is online now   Reply With Quote
Old 08-06-2020, 06:25 PM   #9
jkooks
Human being with feelings
 
Join Date: May 2020
Posts: 190
Default

Ah, yeah, that all does make sense and I can see the added difficulty to implementing something like that. I mainly just wanted to see if this was still an issue or if I was missing an API function/update, or whether or not someone had found a workaround.

Thank you for the response and explanation though! That does help explain why it is an issue in the first place and why it doesn't work like scripts without a defer function, like I hoped it would when I first tried.
jkooks is offline   Reply With Quote
Old 08-07-2020, 09:51 AM   #10
Meo-Ada Mespotine
Human being with feelings
 
Meo-Ada Mespotine's Avatar
 
Join Date: May 2017
Location: Leipzig
Posts: 6,629
Default

I never tried to use UNDO in defer-scripts but if it's not possible at all, I would suggest at least a "Create UndoPoint Per DeferCycle" so at least some undoing would be possible.
So if one defer-cycle changes stuff depending on some events happening, I could undo the stuff immiedately without the consistency issues.

Would not be perfect and far away from what lokasenna asked for but one step closer at least.

But as I said, maybe it's possible already but I never tried.
__________________
Use you/she/her.Ultraschall-Api Lua Api4Reaper - Donate, if you wish

On vacation for the time being...
Meo-Ada Mespotine is online now   Reply With Quote
Old 08-07-2020, 10:36 AM   #11
jkooks
Human being with feelings
 
Join Date: May 2020
Posts: 190
Default

It seems like undoing something as a whole within a defer loop works, to the limited degree of it creates a beginning undo point but never creates the end point. So you can undo the immediate changes that were created within the defer loops, it just won't have an accurate description (it shows as "ReaScript: Run") and you won't be able to redo the entire change if needed. In my case, redoing the action only changes the first item that was adjusted, rather than every single item that had been changed.

And as for what you mentioned earlier, I know I would be fine with undo points that are created while a defer loop's point is still open - effectively becoming "one" with the open defer undo point (i.e. they all become part of the defer loop's state change/point rather than create multiple points), but I know that is pretty specific to how I use defer loops and may not necessarily be everyone else's ideal. But yeah, I get why this hasn't been implemented, both due to the fact that my workflow/need for the feature isn't one to one with everyone else's and the fact that it would be a very complex system to make anyway.
jkooks is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -7. The time now is 04:59 AM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.