Bracket Highlighting in Delphi 12.0 Using SynEdit
Delphi 12.0 users have a new tool to improve code readability: a procedure for enabling bracket highlighting in SynEdit. This feature helps developers quickly identify matching parentheses, braces, and other types of brackets within their code, which is essential for navigating complex code structures efficiently.
To implement this feature, developers need to associate a custom procedure with the OnPaintTransient event in SynEdit. This approach was inspired by discussions and solutions shared in a bug report on the SynEdit project page on SourceForge (sourceforge.net/p/synedit/bugs/358/#bc9e), which pointed out the necessity of visually distinguishing matching brackets.
This functionality enhances the coding experience by making it easier to track nested structures, thus reducing errors and improving development speed. For Delphi 12.0 developers looking to enhance their coding environment, integrating bracket highlighting with SynEdit offers a practical solution.
procedure TfrmSQLAnalizer.SynSQLPaintTransient(Sender: TObject; Canvas: TCanvas;
TransientType: TTransientType);
var
Editor: TSynEdit;
OpenChars: array of WideChar;//[0..2] of WideChar=();
CloseChars: array of WideChar;//[0..2] of WideChar=();
Attri: TSynHighlighterAttributes;
function IsCharBracket(AChar: WideChar): Boolean;
begin
case AChar of
'{',
'[',
'(',
'<',
'}',
']',
')',
'>':
Result:= True;
else
Result:= False;
end;
end;
function CharToPixels(P: TBufferCoord): TPoint;
begin
Result:=Editor.RowColumnToPixels(Editor.BufferToDisplayPos(P));
end;
procedure SetCanvasStyle;
begin
Editor.Canvas.Brush.Style:= bsSolid; //Clear;
Editor.Canvas.Font.Assign(Editor.Font);
Editor.Canvas.Font.Style:= Attri.Style;
if (TransientType = ttAfter) then begin
Editor.Canvas.Font.Color:= clRed; // FBracketFG;
Editor.Canvas.Brush.Color:= cl3DLight;
end
else begin
Editor.Canvas.Font.Color:= Attri.Foreground;
Editor.Canvas.Brush.Color:= Attri.Background;
end;
if (Editor.Canvas.Font.Color = clNone) then
Editor.Canvas.Font.Color:= Editor.Font.Color;
if (Editor.Canvas.Brush.Color = clNone) then
Editor.Canvas.Brush.Color:= Editor.Color;
end;
var
P : TBufferCoord;
Pix: TPoint;
D : TDisplayCoord;
S : String;
I,
ArrayLength,
start: Integer;
TmpCharA,
TmpCharB: WideChar;
begin
try
// if Memo1.InReplaceStatus = False then
// begin
(*
if fMain.SyntaxHEnabled = False then exit;
if Memo1.Highlighter = nil then exit;
if fMain.BracketMatching = False then exit;
if TSynEdit(Sender).SelAvail then exit;
*)
Editor:= TSynEdit(Sender);
ArrayLength:= 3;
(*
if (Editor.Highlighter = SynHTMLSyn1) or (Editor.Highlighter = SynXMLSyn1) then
inc(ArrayLength);
*)
SetLength(OpenChars,
ArrayLength);
SetLength(CloseChars,
ArrayLength);
for i:= 0 to ArrayLength - 1 do
Case i of
0: begin
OpenChars[i]:= '(';
CloseChars[i]:= ')';
end;
1: begin
OpenChars[i]:= '{';
CloseChars[i]:= '}';
end;
2: begin
OpenChars[i]:= '[';
CloseChars[i]:= ']';
end;
3: begin
OpenChars[i]:= '<';
CloseChars[i]:= '>';
end;
end;
P:= Editor.CaretXY;
D:= Editor.DisplayXY;
Start:= Editor.SelStart;
if (Start > 0) and
(Start <= length(Editor.Text)) then
TmpCharA:= Editor.Text[Start]
else
TmpCharA:= #0;
if (Start < length(Editor.Text)) then
TmpCharB:= Editor.Text[Start + 1]
else
TmpCharB:= #0;
if not IsCharBracket(TmpCharA) and
not IsCharBracket(TmpCharB) then
Exit;
S:= TmpCharB;
if not IsCharBracket(TmpCharB) then begin
P.Char:= P.Char - 1;
S:= TmpCharA;
end;
Editor.GetHighlighterAttriAtRowCol(P,
S,
Attri);
if (Editor.Highlighter.SymbolAttribute = Attri) then begin
for i:= low(OpenChars) to High(OpenChars) do begin
if (S = OpenChars[i]) or
(S = CloseChars[i]) then begin
Pix:= CharToPixels(P);
SetCanvasStyle;
Editor.Canvas.TextOut(Pix.X,
Pix.Y,
S);
P := Editor.GetMatchingBracketEx(P);
if (P.Char > 0) and
(P.Line > 0) then begin
Pix:= CharToPixels(P);
if Pix.X > Editor.Gutter.RealGutterWidth then begin
SetCanvasStyle;
if S = OpenChars[i] then
Editor.Canvas.TextOut(Pix.X,
Pix.Y,
CloseChars[i])
else
Editor.Canvas.TextOut(Pix.X,
Pix.Y,
OpenChars[i]);
end; //if Pix.X >
end; //if (P.Char > 0)
end; //if (S = OpenChars[i])
end; //for i:= low(OpenChars)
Editor.Canvas.Brush.Style := bsSolid;
end; //if (Editor.Highlighter.SymbolAttribute = Attri)
except
// TODO
end; //try
end;