[Lazarus] implicit undo (attn Flávio) [Re: Code Structure / SourceEdit and SyneEdit]

Hans-Peter Diettrich DrDiettrich1 at aol.com
Wed Mar 4 18:13:06 CET 2009


Martin Friebe schrieb:

>> My vision deviates a bit from this in the sense that TAbstractSynEdit
>> would just be an abstraction (or dedicated implementation) of a
>> cleaner text manipulation interface (as TStrings won't cut it), which
>> would also implement transparent/automatic/implicit 'undo' handling.
>> Then each command would be a class, probably inheriting from TAction.
>>   
> Just read this, ....
> 
> I had the same idea, and am in progress with something like this.
> I needed it to abstract layers of functionality. for example trimming 
> trailing spaces. If it should work as a transparent plugin it needs 
> access to undo/redo.

IMO an abstract base class better should be a viewer, without text 
manipulation commands. This would allow to sort out problems related to 
undo/redo for debugging.

> My current approach is:
> 
> - I separated SynEdit.Lines from the internal textbuffer (so textbuffer 
> has no longer a need to be TStrings based (it still is, because i didn't 
> take the time to change it))

The TStrings approach isn't really bad. The virtual Get method can 
access any kind of buffer, and we don't have to introduce new names for 
the basic methods and properties, reducing possible confusion of the 
users of the component.

> - I add a few basic methods such as
>   InsertText(x,y, substring); DeleteText,(x,y, len) ; BreakLine, 
> JoinLine (maybe InsertNewLine, DeleteEntireLine)  [*]

In my CharGrid I use a single basic function for insertion and deletion, 
with the Len indicating insertion (> 0) or deletion (< 0). This delta 
can be used to adjust the text size, also with undo/redo operations.

It might be necessary to distinguish clearly between display and text 
positions, where display positions take into account folded blocks, tab 
expansion etc., which only affect the display. While display coordinates 
may be separated into row and column, other positions (bookmarks...) 
better should be given as single text/file offsets. [Where IMO 32 bits 
are sufficient for *text* file size/positions - a dedicated data type 
will allow for eventual customization]

>   - they can deal with undo and redo
>   - In SynEdit all operations can be reduced to the above (and don't 
> care about undo/redo)

The undo/redo capabilities can be encapsulated in the text buffer object 
implementation, only the related methods have to be added to the 
TStrings interface.

> Since TrailingSpaces is already a wrapper around the TextBuffer, it can 
> simply intercept those methods, and deal with them.

Such a wrapper IMO disallows to change the trim option at runtime. I'd 
implement it only in the display code.


> ----
> The only flaw I still have with this is, that currently all the 
> SynEditText* (wrappers around the actual textbuffer, doing, spaces, 
> tabs, folding....) are combining Display and Edit functionality.
> 
> It would be nice to be able to write a TSynDisplay class first, and 
> inherit the editor from it....

FACK

> [*]
> of course insertText could detect newlines, but it  adds complexity. It 
> will be simpler if SynEdit keeps control of this level, and InsertText, 
> only operates on the current line

As mentioned above, a single text offset value is sufficient for all 
text (buffer) operations. The text buffer must not necessarily be 
organized by lines, the object *only* has to map between line numbers 
and text positions for display references. Two such mapping functions 
are required, one for absolute lines in the entire text (in the text 
buffer object), and another one for virtual (folded) display row numbers 
(in the block folding object).

DoDi




More information about the Lazarus mailing list