Hi John,
> Wing has implemented saving and restoring of selection state along with the first visible line for some time.
Restoring the top line is an addition to selection state that I hadn't
been considering. There could be issues in wrap mode with restoring
into a window that had been narrowed or widened.
> The implementation is in Python, though so it can’t be easily contributed to scintilla itself.
A built-in save selection may not have all your features (like top
line) so shouldn't stop a container-side implementation.
> State is saved on a per view basis and then restored on the view that the undo / redo is invoked for.
One common scenario is where a primary view can be split vertically
(or horizontally), perhaps by dragging a splitter down. The user can
edit two portions of the file easily and then collapse back to one
view by dragging the splitter to the top or bottom. The surviving view
is the successor and should restore selections as the corresponding
actions are undone. The surviving view may be the first or second
view, depending on the direction of collapse. The collapsed view may
later be restored with another splitter drag.
This could be implemented by associating each view with a primary view
ID that marks the selection states that it sends to undo history, and
a set of receiving view IDs that it is the current successor to and
responds to. A simpler alternative is to just support simpler
scenarios well with a view either responding just to its own ID or to
every ID. This handles the common case where there are up to 2 true
editing views along with some more static views like document maps or
thumbnails that do not permit selection and so do not contribute
selection states to undo.
While Document could vend view ID cookies to each view that subscribes
to selection state, it may be better for the application to set view
IDs so they are more stable and can be saved into undo history files.
> The number of selection states saved is capped so memory use shouldn’t grow without bound.
Multiple selection and rectangular selection can increase the cost of
this feature.
For rectangular selection, just the rectangular type tag, anchor, and
caret should be saved with the expansion into a vector of per-line
ranges omitted then recalculated after restore. If each per-line range
was saved then the result could be huge - some users perform
whole-file rectangular operations on large data files. This reduction
of rectangular selections may occasionally produce anomalous results
when view parameters like font are changed.
> One wrinkle is that when doing a redo, the selection state after the modification is made to the buffer should be restored. The after selection state is not readily available when a new action is started so it is recorded at the next update-ui notification.
Since it is the view maintaining complex selections like rectangular
or multiple selection, there is no place within the document code that
can ask for the after change selection state. Each piece of view (and
container?) code that changes document text could add a call to save
the after selection state once that is set completely but that would
be a lot of added calls.
If an 'after' selection state is saved then another change made that
is considered part of that user operation then the first selection
state will never be used so should be deleted.
Intense editing operations like replace all will expose the costs of
producing selection states so selection state production should be
avoided where possible. Inside a BeginUndoAction .. EndUndoAction
group, selection state should only be created and saved for the final
top-level EndUndoAction.
> This has some flaws, but seems to work well enough.
There'll be some breakage when multiple user operations occur together
and it would be better to avoid that. Inside Scintilla, there can be a
handler at the end of processing each message (perhaps an object
destructor that is called on return from ScintillaBase::WndProc) that
saves selection state if the document changed and is not currently
inside an undo group.
Neil