Lexilla icon Scintilla

Scintilla Change History.

The concept

Change History is a common feature of IDEs like Visual Studio and Qt Creator showing where a file has been changed with coloured markers in the margin.

Qt Creator showing 2 saved changes and one unsaved change.
Change History in Qt Creator

Visual C++ showing a saved change, a change that was saved but then reverted back to the file start state, and an unsaved change.
Change History in Visual C++

A line may contain changes that are in different states and these are commonly shown with the most consequential taking priority so a line with both saved and unsaved changes will show the unsaved marker.

History states: Origin, Save Point, Reverting, Detached

Initially, the loaded document is in its original state with no changes. When the user inserts, delete or modifies text, the lines affected are marked as changed with (commonly) a yellow bar in the margin.

When the user performs an undo, the change marks may disappear if there are now no changes on that line. Perform a redo and more changes may be marked.

When the document is saved to disk, all changed lines are marked green to indicate they have changes that have been saved. This position is remembered as the 'save point'.

As the user makes more changes, these are shown in the margin. When there are both saved and unsaved changes on a line, the margin indicates unsaved as that is more consequential. Subsequent saves will modify the unsaved marker to the saved marker.

If the user performs undo enough times to go before the save point, then they are 'reverting' changes in the save. These reversions are marked in the margin as reverted, often with the same marker as changed. Lines that are reverted all the way back to their original state may be shown with a different marker as reverted to origin. Visual C++ 2022 shows this as a light blue box with diagonal stripes.

If, while reverting, the user performs a change, this starts a new branch in the document history. The undo information after this branch point is discarded and it is no longer possible to reach the save point. The document is now 'detached' from its saved state.

Plan

Scintilla should include an optional change history feature that is similar to other applications but that may optionally highlight the text that has been inserted and positions where text was removed.

SciTE showing an unsaved change, a saved change, a change that was saved then reverted to unsaved, and a change that was saved but then reverted back to the file start state.
The coloured underlines indicate text that was inserted and there is a small triangle at the end of the underlined "bool" indicating that text was deleted there.
The cyan underlined "noexcept" shows that this text was removed from the version of the file now on disk but has been restored by performing undo.
Change History in SciTE

There are 5 states possible in the Scintilla implementation ordered by visibility with later states overriding earlier:

OriginalClear
Reverted to OriginalCyan
SavedGreen
UnsavedDark Yellow
Reverted to UnsavedOrange

Applications may not want to display all these states or differentiate them - Unsaved and Reverted to Unsaved have similar appearance in Visual C++. Qt Creator uses the same appearance for Unsaved and Reverted to Original. The application can set the margin marker, insertion indicator, and deletion indicator of each state except Original. Any element states not set by the application will not be visible.

The small triangles used to indicate deletions aren't very prominent with colours difficult to tell apart. Some other visual may be better.

There is a mostly working implementation available and shown above.

The memory overhead of enabling change history is moderate and will scale based on number of changes in the editing session. The current implementation is simple and could be more efficient in its use of memory. There is at least one 'position sized' (32 or 64-bit) integer 'element' for each deletion action; a run-length representation of all the insertions (4 * element for each run); 2 * element for each deletion + a std::vector (maybe 4 * element + any overallocation) at each point of deletion; memory of earlier changes in undo history takes around 4 * element for each item moved from current state to memory.

Deleted Text

While the text of insertions is visible, this isn't the case for deletions. There could be a popup window displaying deleted text when hovering over a deletion marker but this will require more development and some way to reconstruct the text in a reasonable form from multiple deletion events. The deletions may occur in reverse text order if the user, for example, holds down the backspace key.

Deleted text could also be shown inline with strikeout or greying or similar. This doesn't work so well when multiple lines are deleted.

Prehistory

As well as the current editing session, it can be useful to see where changes have been made to the text in the past. I would like to see what has changed since the last commit in one colour and changes between the last release and last commit in another. Others may want to see recent changes by other team members in different colours or some other differentiation. As an extreme, each change set in a repository could have its own 'edition' in the file that could be queried and shown in a range of colours.

SciTE showing changes from the history of the file before it was opened.
Prehistory in SciTE

The implementation currently allows two prehistoric editions (-1 and -2). The number of editions to support is to be determined but will have implications with how to define visuals. With just 4 base states and a couple of prehistoric editions, a range of current marker and indicator numbers can be dedicated to change history states. If there were (around) 32 prehistoric editions, then a second set of markers/indicators could be added for this purpose. If thousands (or millions) of editions were desired then something stronger may be needed.

Prehistory could be uncovered by examining git change logs and similar although such tools often produce only per-line change information. There are tools like WinMerge that show changes in per-character detail so its likely that there is code available to produce detailed edition logs that can be loaded into Scintilla's change history.

Earlier discussions

Experimental change bar feature
determinate editing line undo status
Availability of changebar-enabled SciTE
Any support planed for a Change Margin ?