YOUSEFUL / DELPHI / COMPONENTS

TAtlasSyntaxMemo

Rich Edit control that colours Object Pascal source as you type and keeps its own text-only undo and redo history.

Visual control Palette: Atlas UI Unit Atlas.Syntax · Inherits TRichEdit · Product Atlas UI

Description

A TRichEdit set up for source code: plain text, no word wrap, both scroll bars, Tab inserts a tab, Consolas 11, 700 by 450 pixels. Every other property, method and event of TRichEdit (Text, Lines, SelStart, ReadOnly, OnChange, ...) works as usual.

Highlighting. After every text change the whole text is tokenized with AtlasPascalTokens and coloured with AtlasTokenColor: keywords dark blue and bold, strings dark red, comments green, numbers purple, everything else near-black. The caret, the selection, the scroll position and the Modified flag are preserved. Highlighting needs a window, so it only runs once the editor has a Parent: text assigned before that stays uncoloured until the next change or a call to Highlight. See TAtlasTokenKind for exactly what the lexer recognizes. It is a lexer, not a parser: there is no code completion, error marking, folding, line numbers, bracket matching or support for other languages.

Undo. The editor records a copy of the whole text after each change, up to 128 copies, and UndoText and RedoText step through them. Ctrl+Z, Ctrl+Y and Ctrl+Shift+Z, the WM_UNDO, EM_UNDO and EM_REDO messages, and the inherited Undo and CanUndo all use this history instead of the Rich Edit one, so colouring never becomes an undo step. Undo and redo restore the text only: the caret moves to the end and colours are recomputed. A new edit after an undo discards the redo steps. The history starts with the empty text the editor had when it was created and there is no method to clear it, so undoing past a loaded file empties the editor. A read-only editor ignores undo and redo.

Size. Each change re-colours the whole text and stores another full copy of it, so the editor suits small and moderate files. Performance with large files has not been measured.

Members

MemberKindWhat it does
CreateconstructorCreates the editor with PlainText, no WordWrap, ScrollBars set to ssBoth, WantTabs, font Consolas 11, 700 by 450 pixels, and a text history holding the empty text.
DestroydestructorFrees the text history and destroys the control.
HighlightmethodTokenizes the current text and applies the colours now, keeping the caret, selection, scroll position and Modified.
UndoTextmethodRestores the text as it was before the last change, moves the caret to the end and sets Modified.
RedoTextmethodRe-applies the change the last UndoText took back, moves the caret to the end and sets Modified.
CanUndoTextmethodTrue when UndoText has an earlier text to go back to.
CanRedoTextmethodTrue when RedoText has a later text to restore, that is after an undo and before any new edit.
TokensmethodA copy of the tokens found by the last Highlight, covering the whole text.

Constructors

Create constructor

constructor Create(AOwner: TComponent); override;

Creates the editor with PlainText, no WordWrap, ScrollBars set to ssBoth, WantTabs, font Consolas 11, 700 by 450 pixels, and a text history holding the empty text.

Destructors

Destroy destructor

destructor Destroy; override;

Frees the text history and destroys the control.

Methods

Highlight method

procedure Highlight;

Tokenizes the current text and applies the colours now, keeping the caret, selection, scroll position and Modified. The editor calls it after every change; call it yourself after assigning Parent to an editor that already has text. Does nothing while the editor has no Parent, or when called during its own formatting.

pascal
Editor.Parent := Self;
Editor.Highlight;

UndoText method

procedure UndoText;

Restores the text as it was before the last change, moves the caret to the end and sets Modified. Does nothing when there is nothing to undo or the editor is read-only.

pascal
if Editor.CanUndoText then
  Editor.UndoText;

RedoText method

procedure RedoText;

Re-applies the change the last UndoText took back, moves the caret to the end and sets Modified. Does nothing when there is nothing to redo or the editor is read-only.

CanUndoText method

function CanUndoText: Boolean;

True when UndoText has an earlier text to go back to. The inherited CanUndo returns the same value.

CanRedoText method

function CanRedoText: Boolean;

True when RedoText has a later text to restore, that is after an undo and before any new edit.

Tokens method

function Tokens: TArray<TAtlasToken>;

A copy of the tokens found by the last Highlight, covering the whole text. Start is the 0-based character position in the editor, with each line break counted as one character, so it can be assigned to SelStart directly. Empty until the first highlight.

pascal
for Token in Editor.Tokens do
  if Token.Kind = atkComment then
    Inc(CommentCount);

Examples

A Pascal editor with Undo and Redo buttons

A form built in code. The editor gets its Parent before any text, so loaded files are coloured at once, and OnChange keeps the buttons in step with CanUndoText and CanRedoText. Call LoadFile with the name of a .pas file after creating the form.

pascal
uses System.SysUtils, System.Classes, System.IOUtils, Vcl.Forms, Vcl.Controls, Vcl.StdCtrls, Vcl.ExtCtrls,
  Atlas.Syntax;

type
  TSourceForm = class(TForm)
  private
    FEditor: TAtlasSyntaxMemo;
    FUndo, FRedo: TButton;
    procedure EditorChange(Sender: TObject);
    procedure UndoClick(Sender: TObject);
    procedure RedoClick(Sender: TObject);
  public
    constructor Create(AOwner: TComponent); override;
    procedure LoadFile(const FileName: string);
  end;

constructor TSourceForm.Create(AOwner: TComponent);
var
  Bar: TPanel;
begin
  inherited CreateNew(AOwner);
  Caption := 'Source';
  Width := 800;
  Height := 600;
  Bar := TPanel.Create(Self);
  Bar.Parent := Self;
  Bar.Align := alTop;
  Bar.Height := 40;
  FUndo := TButton.Create(Self);
  FUndo.Parent := Bar;
  FUndo.SetBounds(8, 6, 80, 28);
  FUndo.Caption := 'Undo';
  FUndo.OnClick := UndoClick;
  FRedo := TButton.Create(Self);
  FRedo.Parent := Bar;
  FRedo.SetBounds(96, 6, 80, 28);
  FRedo.Caption := 'Redo';
  FRedo.OnClick := RedoClick;
  FEditor := TAtlasSyntaxMemo.Create(Self);
  FEditor.Parent := Self;          // before any text: highlighting needs a parent
  FEditor.Align := alClient;
  FEditor.OnChange := EditorChange;
  EditorChange(nil);
end;

procedure TSourceForm.LoadFile(const FileName: string);
begin
  FEditor.Text := TFile.ReadAllText(FileName);
  FEditor.Modified := False;
end;

procedure TSourceForm.EditorChange(Sender: TObject);
begin
  FUndo.Enabled := FEditor.CanUndoText;
  FRedo.Enabled := FEditor.CanRedoText;
end;

procedure TSourceForm.UndoClick(Sender: TObject);
begin
  FEditor.UndoText;
  FEditor.SetFocus;
end;

procedure TSourceForm.RedoClick(Sender: TObject);
begin
  FEditor.RedoText;
  FEditor.SetFocus;
end;

TAtlasToken · TAtlasTokenKind

Also in Atlas UI

TAtlasKanbanModel · TAtlasKanban · TAtlasWebUpdater