AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Source Code Formater

Ein Thema von Monday · begonnen am 17. Aug 2015 · letzter Beitrag vom 10. Jul 2021
Antwort Antwort
Monday

Registriert seit: 24. Aug 2012
103 Beiträge
 
FreePascal / Lazarus
 
#1

AW: Source Code Formater

  Alt 11. Jul 2020, 20:35
Hallo,

ist schon eine Weile her. Aber mein Wunsch einen eigenen Source Code Formatter (Pascal) zu schreiben steht noch immer im Raum

Deshalb habe ich noch ein bisschen gegrübelt und mich mal wieder daran versucht.

Einer meiner ersten Versuche möchte ich hier vorstellen. Es ist eine reine Spiel-und-Test Version. Es funktioniert noch nicht perfekt. Aber mir gefällt die Tendenz im Augenblick schon ganz gut. Später wenn ausgereifter will ich alles auch benutzerfreundlicher machen. Aktuell muss ich den Zustand reifen lassen

Wer Lust und Spaß daran hat, kann gerne mit dem Code auch etwas herumknobbeln, weiterverarbeiten, usw.
Anregungen zum Code und Ideen sind Willkommen.

Der Code ist einfach gehalten. Einfach ein neues Projekt erstellen, ein großes Memo (nur für die Anzeige), ein Button und ein Label (eigentlich auch nicht notwendig, wieder nur um schnell mal etwas zu prüfen...) darauf ziehen. (Ich komme von Lazarus, daher sind evtl. geringfügig änderungen nötig).

"input.txt" => Quellcode der formatiert werden soll
"output.pas" => der Formatierter Code

Viel Spaß und viel Glück

Delphi-Quellcode:
unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls,RegExpr, strutils;

type

  { TForm1 }

  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Label1: TLabel;
    Memo2: TMemo;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private

  public

  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }


function string_zaehlen(substr: string; str: string): integer;
var
  a: integer;
  z,posi: integer;
begin
  // ===== Ein paar sachen nicht zählen:
  // === einzeiliges...
  // kommentare ignorieren
  Delete(str,pos('//',str),length(str));
  // texte innerhalb von ' ignorieren
  Delete(str,posEx('''',str,1),
    (posEx('''',str, posEx('''',str,1)+1 ) - posEx('''',str,1)+1 ) );



  // ab hier zählen
  z := 0; posi := 0;
  For a := 0 to str.Length-1 do begin
    posi := posEx(substr, str, posi+1);
    if posi > 0 then begin
      z := z+1;
    end;
    if posi = 0 then begin break; end;
  end;
  Result := z;
end;

//https://www.delphi-treff.de/tipps-tricks/object-pascal/strings/zeichen-wiederholen/
function Replicate(ch: char; anzahl: integer): string;
begin
  SetLength(Result,Anzahl);
  if Length(Result)>0 then
    FillChar(Result[1],Length(Result),ch);
end;

procedure Split(Delimiter: Char; Str: string; ListOfStrings: TStrings) ;
begin
   ListOfStrings.Clear;
   ListOfStrings.Delimiter := Delimiter;
   ListOfStrings.StrictDelimiter := True; // Requires D2006 or newer.
   ListOfStrings.DelimitedText := Str;
end;


function Implode(const Strings: TStrings; const separator: string): String;
var
  i: Integer;
begin
  Result := Strings[0];
  for i := 1 to Strings.Count - 1 do
    Result := Result + separator + Strings[i];
end;


procedure TForm1.Button1Click(Sender: TObject);
var
  input: TSTringList; // Datei einlesen
  output: TStringList; // verarbeitete daeti ausgeben

  trenner: TSTringList;

  a: integer;
  temp,txt,txt2: string;

  leerzeichen: integer;
  d: textfile;
begin


  // ===== Datei einlesen - begin
  input := TStringList.Create;
  input.LoadFromFile('input.txt');
  // ===== Datei einlesen - end







  // ===== Datei verarbeiten - begin
  trenner := TStringList.Create;
  trenner.Add(' ');
  trenner.Add('//');
  trenner.Add(';');
  trenner.Add('var');
  trenner.Add(#13#10);
  trenner.Add('begin');
  trenner.Add('end');
  trenner.Add('{');
  trenner.Add('}');
  trenner.Add('[');
  trenner.Add(']');
  trenner.Add('(');
  trenner.Add(')');
  trenner.Add('"');
  trenner.Add('''');


  txt := input.Text;
     For a := 0 to trenner.Count-1 do begin
  txt := StringReplace(txt,trenner[a],#13#10+trenner[a]+#13#10,[rfReplaceAll, rfIgnoreCase]);
  end;

     input.text := txt;
     input.Text.Split(#13#10);



  // === Elemente prüfen und bearbeiten
  For a := 0 to input.Count-1 do begin




     // allgemeines
    if pos('interface',input.Strings[a]) >0 then begin input.Strings[a] := #13#10#13#10+'interface'+#13#10; end;
    if pos('uses',input.Strings[a]) >0 then begin input.Strings[a] := #13#10+'uses'+#13#10; end;
    if pos('type',input.Strings[a]) >0 then begin input.Strings[a] := #13#10+'type'+#13#10; end;
    if pos('private',input.Strings[a]) >0 then begin input.Strings[a] := #13#10+'private'+#13#10; end;
    if pos('public',input.Strings[a]) >0 then begin input.Strings[a] := #13#10+'public'+#13#10; end;
    if pos('implementation',input.Strings[a]) >0 then begin input.Strings[a] := #13#10+'implementation'+#13#10; end;
    //if pos('type',input.Strings[a]) >0 then begin input.Strings[a] := #13#10+'type'+#13#10; end;



    // ===== Zeilenumbrüche
    // Zeilenumbruch aber nicht weniger Text als X zeichen ist.
    if posEx('var',input.Strings[a],1) >0 then begin input.Strings[a] := StringReplace(input.Strings[a],'var',#13#10+'var'+#13#10,[rfReplaceAll, rfIgnoreCase]); end;
    //if posEx('begin',input.Strings[a],1) >0 then begin input.Strings[a] := StringReplace(input.Strings[a],'begin','begin '+#13#10,[rfReplaceAll, rfIgnoreCase]); end;
    if posEx('begin',input.Strings[a],1) >0 then begin input.Strings[a] := StringReplace(input.Strings[a],'begin','begin'+#13#10,[rfReplaceAll, rfIgnoreCase]); end;
    if posEx('end;',input.Strings[a],90) >0 then begin input.Strings[a] := StringReplace(input.Strings[a],'end;',' end;'+#13#10#13#10,[rfReplaceAll, rfIgnoreCase]); end;
    if (posEx('procedure',input.Strings[a],1) >0) then begin input.Strings[a] := StringReplace(input.Strings[a],'procedure',#13#10#13#10#13#10+'procedure',[rfReplaceAll, rfIgnoreCase]); end;
  if posEx('function',input.Strings[a],1) >0 then begin input.Strings[a] := StringReplace(input.Strings[a],'function',#13#10#13#10#13#10+'function',[rfReplaceAll, rfIgnoreCase]); end;

  if posEx('if',input.Strings[a],1) >0 then begin input.Strings[a] := StringReplace(input.Strings[a],'if',#13#10+'if',[rfReplaceAll, rfIgnoreCase]); end;
  if posEx('while',input.Strings[a],1) >0 then begin input.Strings[a] := StringReplace(input.Strings[a],'while',#13#10+'while',[rfReplaceAll, rfIgnoreCase]); end;
  if posEx('for',input.Strings[a],1) >0 then begin input.Strings[a] := StringReplace(input.Strings[a],'for',#13#10+'for',[rfReplaceAll, rfIgnoreCase]); end;


  temp := input.Strings[a];
  //Delete(temp,pos('//',temp),length(temp)); // kein zeilenumbruch im kommentar
  if (posEx(';',temp,1) >0) then begin input.Strings[a] := StringReplace(input.Strings[a],';',';'+#13#10,[rfReplaceAll, rfIgnoreCase]); end;
  end;
  // ===== Datei verarbeiten - end




  // ===== leerzeichen - begin
  // leerzeichen muss am schluss gemacht werden

  // === Vorformatieren - begin
   output := TStringList.Create;
   txt2 := '';
    For a := 0 to input.Count-1 do begin
      txt2 := (txt2+input.Strings[a]);
    end;
    output.text := txt2;
    output.text.Split(#13#10); //jetzt zeilenweiße bearbeitne
  // === Vorformatieren - end



  leerzeichen := 1; // linker rand
  For a := 0 to output.Count-1 do begin
    output.strings[a] := trimleft(output.strings[a]);



    temp := StringReplace(output.strings[a],'end;','endXXX',[rfReplaceAll, rfIgnoreCase]);
    temp := StringReplace(temp,'end ','endXXX',[rfReplaceAll, rfIgnoreCase]);
    leerzeichen := leerzeichen - string_zaehlen('endXXX',temp);
    //leerzeichen := leerzeichen - string_zaehlen('end;',temp);


    //output.strings[a] := IntTostr(leerzeichen)+Replicate(' ',leerzeichen) + output.strings[a]; //zum testen
    output.strings[a] := Replicate(' ',leerzeichen) + output.strings[a];


    leerzeichen := leerzeichen + string_zaehlen('begin',output.strings[a]);
    leerzeichen := leerzeichen + string_zaehlen('class(',output.strings[a]);
    leerzeichen := leerzeichen + string_zaehlen('finally',output.strings[a]);



    label1.caption := IntToStr(leerzeichen); //zum testen ob leerzeichen noch stimmen...

    output.strings[a] := output.strings[a]+#13#10;


  end;



  // ===== Schönheitskorrekturen
  // leerzeilen korrigieren
  For a := output.Count-1 downto 0 do begin

     // procedure zusätzliche leerzeilen wieder entfernen / korrigieren
    if (pos('procedure',output.strings[a]) > 0) and ((trim(output.strings[a-1]) = '')) and (pos('procedure',output.strings[a-4]) > 0) then begin
      output.Delete(a-1);
      output.Delete(a-2);
      output.Delete(a-3);
    end;

    // var zusätzliche leerzeilen wieder entfernen / korrigieren
   if (pos('var',output.strings[a]) > 0) and (trim(output.strings[a-1]) = '') then begin
     output.Delete(a-1);
   end;

  end;

input := output;

  // ===== leerzeichen - end






  // ===== Temporär anzeigen - begin
  Memo2.text := ''; txt2 := '';
  For a := 0 to input.Count-1 do begin
    //txt2 := (txt2+input.Strings[a])+#13#10; // anzeige um die einzelnen objekte zu erkennen.
    txt2 := (txt2+input.Strings[a]);
  end;
  Memo2.text := txt2;
  // ===== Temporär anzeigen - end





  // ===== Datei schreiben - begin
  assignfile(d, 'output.pas');
  rewrite(d);
  writeln(d, txt2);
  closefile(d);
  // ===== Datei schreiben - bend
end;
  Mit Zitat antworten Zitat
Benutzerbild von Mavarik
Mavarik

Registriert seit: 9. Feb 2006
Ort: Stolberg (Rhld)
4.154 Beiträge
 
Delphi 10.3 Rio
 
#2

AW: Source Code Formater

  Alt 12. Jul 2020, 11:22
Hallo,

ist schon eine Weile her. Aber mein Wunsch einen eigenen Source Code Formatter (Pascal) zu schreiben steht noch immer im Raum
Ja ich bin auch immer noch dabei - wenn Zeit ist.

Gut mein Formatter ist deutlich aufwendiger als Deiner...

Die Delphi Frühstücksgruppe ist mittlerweile auch dabei.

Mavarik
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.346 Beiträge
 
Delphi 12 Athens
 
#3

AW: Source Code Formater

  Alt 12. Jul 2020, 13:26
Habt ihr euch mal versucht ans LSP zu hängen?
Das ware doch eine gute Ausgangslage auch für einen Formatter.
Ein Therapeut entspricht 1024 Gigapeut.
  Mit Zitat antworten Zitat
freimatz

Registriert seit: 20. Mai 2010
1.490 Beiträge
 
Delphi 11 Alexandria
 
#4

AW: Source Code Formater

  Alt 13. Jul 2020, 07:56
Hallo,

ist schon eine Weile her. Aber mein Wunsch einen eigenen Source Code Formatter (Pascal) zu schreiben steht noch immer im Raum
Dann beschäftige Dich mal mit Grammatiken und Parser. Sonst wird das immer ein unbrauchbares Gebastel bleiben.

Und warum nicht den Delphi eigenen Formatter verwenden?
  Mit Zitat antworten Zitat
Benutzerbild von Mavarik
Mavarik

Registriert seit: 9. Feb 2006
Ort: Stolberg (Rhld)
4.154 Beiträge
 
Delphi 10.3 Rio
 
#5

AW: Source Code Formater

  Alt 13. Jul 2020, 09:35
Und warum nicht den Delphi eigenen Formatter verwenden?
Weil der nicht genug kann, bzw. nicht das was ich brauche.
  Mit Zitat antworten Zitat
bernhard_LA

Registriert seit: 8. Jun 2009
Ort: Bayern
1.138 Beiträge
 
Delphi 11 Alexandria
 
#6

AW: Source Code Formater

  Alt 8. Jul 2021, 15:54
was ist denn aktuell (2021) der bester code Formater für Delphi ?
  1. ich hätte gerne einheitliche Schreibweise für alle var's , Befehle etc. , also immer so was wie FMeineVar : String; . das F bei Lokalen Vars ist zwingend
  2. typen müssen immer als TMyObject benannt werden
  3. .....
  4. das ganze Formatierungs Thema kann via XML konfiguiert werden


Hab so was bei IntelliJ & Java , wäre auch cool wenn der Delphi Code so ordentlich dann wäre.
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
9.935 Beiträge
 
Delphi 12 Athens
 
#7

AW: Source Code Formater

  Alt 8. Jul 2021, 20:39
Der beste ist finde ich der in Delphi integrierte mit neu eingestellter Breite (z.B. 130 Zeichen, was ich auch im Editor selbst einstelle). Der funktioniert meistens gut und hält sich ohne weitere Einstellungen an die Standardformatierung.
Sebastian Jänicke
AppCentral
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.631 Beiträge
 
Delphi 12 Athens
 
#8

AW: Source Code Formater

  Alt 8. Jul 2021, 20:57
Ein Teil deiner Forderungen hat aber nichts mit der Formatierung zu tun, sondern mit Namenskonventionen. Das wird ein reiner Formatter nicht leisten können.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benutzerbild von Mavarik
Mavarik

Registriert seit: 9. Feb 2006
Ort: Stolberg (Rhld)
4.154 Beiträge
 
Delphi 10.3 Rio
 
#9

AW: Source Code Formater

  Alt 9. Jul 2021, 10:43
Der Formatter der von Delphi mitgeliefert wird, wird von EMBT "gepflegt" und sollte eigentlich immer auf dem aktuellen Stand sein...
Ich einer perfekten Welt.

Mir geht es aber um mehr bei der Sourcecode-Formatierung.

Ich habe schon vor langer Zeit "rumgefragt", wer mir bei der Programmierung des ultimativen Formatters helfen möchte...
Die, die sich gemeldet haben, haben bisher keine einzige Zeile dazu beigetragen.

Da ich meinen Focus momentan auf #DMVVM gelegt habe, komme ich leider selber auch nicht dazu...
Ohne Erklärungen wird man den Source nicht verstehen, daher ist das Repo nicht public.

Ich will Ende des Jahres nochmal einen Blog-post dazu machen und den Fortschritt zeigen.

was ist denn aktuell (2021) der bester code Formater für Delphi ?
Vielleicht kann ich die Frage dann 2022 beantworten.
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 11:27 Uhr.
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz