Undo Document Functions

Hi all,

While reading through the user manual, I noticed that there are a lot of functions in Scrivener — most of them related to Document and/or Binder manipulation — that cannot be undone. (Examples include merging and splitting, conversion to default formatting, many Binder operations, etcetera.) So, my question is, what would it take (developmentally speaking) to enable some of this more advanced “undo” functionality? Maybe work to make these operations less destructive? I was thinking that Scrivener could have a selective “Undo history” the way Adobe Photoshop does; i.e., the software takes a snapshot of whatever parts of the project will need to be restored (but only those parts, and in the background, so that the user isn’t interrupted), and then that “partial snapshot” shows up as an icon in a little tool palette. If the user clicks on an event in the history, the project (or perhaps just the affected part of the project, or just the current document) reverts to that state. I’m sure that programmatically this would be a nightmare . . . or would it? At the very least, I’d like to see at least some of these operations be undoable in the future, as there have been many times I’ve trashed a Document in the binder, converted a file to default formatting, or split a file, and then really wished I could undo it. Is anything like this coming? Is this a good idea, or not?

Thanks,
Andy H.

The Photoshop method is in my opinion really the best way to approach this, mainly because a lot of decisions that are made at this level are not destructive. Splitting isn’t destructive. You can merge two things back together again. Moving an item to the trash is not destructive, grouping or moving items together, likewise. All of these things have sensible reversions either as commands or mirror manipulations. So adding them to the undo stack is superfluous and gets in the way of the really destructive things. And Photoshop isn’t consistent on this. It mixes some interface and non-destructive stuff into a destructive action’s undo row, and that drives me absolutely insane. I can’t stand it when I move a layer above another, then undo a brush stroke I just made and find my layer back below again as well as the brush stroke removed. Those are two separate actions and it means I have to do something “filler” between non-destructive actions and starting a drawing session since I don’t want that first brush stroke (which is often undone until I get my mechanical hand-to-screen feel back) tied to the non-destructive action. I digress into a rant.

Is the Photoshop method really the best for Scrivener though? I mean, that’s a tool that isn’t exactly well known for its ease of use. It commands entire bookshelves in technical bookstores, and is often used as a quasi-pejorative in the statement, “This software is the Photoshop of INSERT TASK…”, where such a statement means, “It does everything conceivable, but don’t expect it to be holding your hand about it.” I think stuff like this: bifurcated silent history, interface state snapshots, composition snapshots, are in the category of “Everything You Need, but Damn.” I could be wrong. I used to live in Photoshop, and it can be hard to tell what is hard to fathom from what is natural to fathom when you know so many aspects of it as second nature. But I forget, I’m from the “anti-all-features” brigade, supposedly (try convincing Keith of that!). :wink:

Here’s one for you: isn’t a total interface + organisation + data snapshot of the project in its current state File/Back Up/Back Up Now... or .../Back Up To...? The only thing missing is an automatic rollback feature in a little floating palette. I’m not knocking that by the way, a backup front-end is something on the future consideration list. I’m just saying, mightn’t that be all we need to do here, make rolling back easier?

Well, yeah, I can see that. My hobby used to be video editing, and I’m most familiar with the undo stack palette from Adobe Premiere, and I often got frustrated by the fact that Final Cut Pro didn’t have one. I’m not necessarily in the ‘pro-all-features’ camp, but rather, I am in the ‘as-many-features-as-it-takes’ category, where “as it takes” is an average of all the most popular requests plus a few other bells and whistles just to be sure, if they’re doable. I don’t buy into the “slippery slope fallacy” when it comes to the issue of feature-bloat when it comes to software design. For one, I think it relies on one’s subjective impression of what exactly constitutes “too many.” :smiley:

I can see where you’re coming from, though. When software gets as complex (and sometimes inconsistent) as Photoshop is, it can become an unwieldy sledgehammer when what is needed is a scalpel. All that aside, though, I am very glad to see that a front-end rollback feature is in the works for Scrivener, though I think it would be nice if it worked way Photoshop’s undo palette does, if coupled to the (already on the list) front-end for a kind of versioning. Reason being, I think it’s a cool idea. But I don’t think that just because Scrivener borrows a really good — if inconsistent — idea from PS, that it’s necessarily selling out to the "too many features to make sense of’ philosophy of software design that PS represents. Rather, I think it’s just a good, sensible idea that would work pretty well, if done right . . . which, as you noted, the undo stack in PS isn’t.

For me, almost all of Scrivener has been very easy to fathom. I’ve been figuring out software since my days on the C64, which helps, but on the whole, it’s been a pretty smooth learning curve for me. I’ve asked questions occasionally on the forums, and have gotten some good responses, and that, together with the (very nicely done, I’ll add) :slight_smile: user manual, has made learning it a joy and a breeze. I actually had a lot of it figured out the first week I worked with it, so I think that unlike Photoshop, Scrivener is still well within the realm of the intuitive and easily-grasped. So, I don’t think a few new features that are a wee bit complex are going to spoil the ease-of-use game that Scrivener has going. (I still discover new uses for it and new ways to do things, and features I didn’t know were there, but it’s usually a pleasant surprise, as in, “Oh, I can do that? Neat!”)

Andy H.

Although as much undo as possible is always a good idea, there are nontrivial, boring technical problems that present significant hurdles for programs like Scrivener allowing undo at every stage. In Scrivener, currently, undo works something like this:

• Each document has its own undo stack for its main text. So, if you make some changes to a document, then go and edit several other documents, then return to it, hitting Undo will undo the changes to that document there in front of you that you edited a little while ago. This makes sense to me, rather than having undo affect text changes you made in documents you can no longer see.

• The binder and the rest of the interface has its own undo stack. This is a bit fragile, though, and gets reset whenever you select a different document in the binder (thus, if you lock the editor and drag things around in the binder, you can undo freely, but not if the document in the editor changes). This is, admittedly.

This last feature of Scrivener is a little odd - undo resetting whenever you switch a document - but it has its roots in the strange way undo works in Cocoa. You might thing that undo is related to the model object - that is, that undo is related to the data. It’s not, though; it’s related to the view. Thus, if you load text into a text view and make changes to it, and then switch to some different text, if you hit undo, the undo manager, which is part of the text view, thinks that text is the text got swapped out, tries to change it, and then you get errors or messed up text. Fortunately, with text views, there is a way of swapping out different undo managers, which is what Scrivener does to avoid this, and which thus allows each main text to have its own undo stack. Even so, the actual process of calling “undo” and “redo” is all handled by the text view itself. So there’s no way for Scrivener to say, "Right, if you hit “undo” now, it should affect the last thing done over here. Instead, whichever view has the focus will grab the undo action if it supports it, and try to call undo on whichever is the active undo stack.

This makes undo very fragile in general when you have a program that has so many different views. If you consider a single document in the binder, it has many different views associated with it: the main text area, the synopsis title field, the synopsis editor, the notes area, the custom meta-data area, the keywords view, the references view and so on. Some of those views support undo off-the-bat and look for the current undo stack, and operate on it; others do not. If they use a single undo stack - as they currently do, sharing the main project undo stack with the binder (except for the main text area, which gets its own undo stack for each document) - then every time you select a different document in the binder, there is suddenly a whole lot of information on the undo stack that is now invalid, because the data associated with it has been swapped out of the associated views (and there is no way to clear only parts of the stack to avoid this). So, calling undo will inevitably thrown an exception. The only solution is to clear the undo stack at these points to avoid errors - which is what currently happens. And it’s not possible for these other views to share the main text view undo stack, either, because having different text areas use the same undo stack without resetting it can cause errors. But giving each of these areas its own undo stack gets very messy. And even if I did that, that doesn’t solve the problem of the binder. Having full undo there could lead to all sorts of problems seeing as it is dealing, behind the scenes, with files on disk. Consider what happens when you create a document in TextEdit and save it into the Finder - you can’t switch to the Finder and undo that action, but have to delete it manually.

So… Full undo gets very tricky with the binder, to say the least. It’s not that I disagree with you that full undo would be lovely, but at the moment these technical considerations make this very difficult. Possibly not insurmountable, but with limited time and resources it becomes a lower priority next to the many other things that need doing, given that things are set up sufficiently so that you generally would have to work quite hard to totally mess up a project in Scrivener and not be able to return it to an earlier state.

Hope that makes sense! (And I hate to sound like a stuck record, blaming everything on technical problems, which admittedly shouldn’t be the user’s concern.)

All the best,
Keith

Thanks for the explanation, Keith. I didn’t know that this was dependent on Cocoa methods, nor did I understand how complex the subject was until now. I see what you mean about it being a thing that would be lovely to have, but given the way Cocoa works — and that you have limited resources — it’s well-nigh impossible to implement easily. I could, of course, suggest you write your own custom undo engine, one that managed all the other stacks as well as performed a few unique functions of its own, but then again, I do recognize that you have time and resource constraints that don’t really lend themselves to that sort of large-scale project, plus you’ve got a lot of other, more directly useful features that you want to implement, plus bugs you want to hunt down. :slight_smile: It makes me wish that there was a stronger grass-roots push to get writers everywhere to adopt Scrivener as their tool of choice (after all, it’s become mine in only a few months), so that you could make more money off of it, so that you could hire more developers, so that you could implement every little feature that each and every one of our little user-hearts desires. Maybe we could organize a massive Facebook posting campaign, or perhaps erect a (separate) Scrivener fansite, or perhaps we could all contribute $5 for a snazzy Google ad? 8)