Things are always more complicated than you first think.
That was the theme for today. I was fixing a pair of functions for inserting time or deleting time. They just either nudge events forward or pull them back. They nudge everything after the selection for the size of the selection, and for convenience if the selection is a point they nudge by the current time step.
Ok, but what if the selection is overlapped by an event? Well, I should shorten or lengthen that event too, since I'm inserting or deleting time in its middle. But wait, if I'm shortening the event and it I can't shorten it more than its total duration, it should at most shorten down to the point where I'm nudging. But wait again, what if the time I'm deleting overlaps with the beginning of an event? Well, I shouldn't delete the whole event, I should only clip off the beginning before shifting it back. Of course, if that means clipping the whole note, then it gets deleted after all. So "simple" event nudging is not so simple after all.
All of this slicing and shifting exposes a weakness in the interface for modifying events in Ui.State, so I wound up rethinking that. The problem is that the traditional definition for a range is half-open, which means that its everything greater or equal than the start but less than the end. However, the nudge commands, along with a fair amount of others, should affect an event directly on the selection even when it's a point, which in a traditional half-open range will never select anything. So I wind up with a function for a range, a function for a point, and a lot of code that checks start==end and tries one or the other. This seemed error-prone so I wanted to have the range functions handle that, but baking a nonstandard exception like that into a primitive function seemed like a bad idea, so I wind up with three versions of each function: one for points, one for ranges, and one point/range hybrid.
So even deleting a range of events is not so simple after all.
Hopefully I can put these somewhat complicated but convenient behaviours into standard utilities. Then commands will behave more uniformly and it will be easier to implement them. So while three versions of each ranged function sounds excessive, I think it's probably best is the long run.