Via Cà Matta 2 - Peschiera Borromeo (MI)
+39 02 00704272
info@synaptica.info

Delphi SynEdit – HighLigth Parenthesis or Bracket

Digital Innovation Partner

Delphi SynEdit – HighLigth Parenthesis or Bracket

Questa funzionalità aiuta i programmatori a identificare rapidamente le parentesi corrispondenti, come parentesi tonde, graffe e altri tipi di parentesi nel loro codice, essenziale per navigare efficientemente tra strutture di codice complesse.

Per implementare questa caratteristica, è necessario associare una procedura personalizzata all’evento OnPaintTransient in SynEdit. Questo approccio è stato ispirato da discussioni e soluzioni condivise in una segnalazione di bug nella pagina del progetto SynEdit su SourceForge (sourceforge.net/p/synedit/bugs/358/#bc9e), che ha evidenziato la necessità di distinguere visivamente le parentesi corrispondenti.

Questa funzionalità migliora l’esperienza di programmazione rendendo più semplice tracciare le strutture nidificate, riducendo così gli errori e migliorando la velocità di sviluppo. Per gli sviluppatori Delphi 12.0 che cercano di potenziare il loro ambiente di codifica, integrare l’evidenziazione delle parentesi con SynEdit offre una soluzione pratica.

 

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;