dexed/src/u_dfmt.pas

362 lines
9.9 KiB
Plaintext

unit u_dfmt;
{$I u_defines.inc}
interface
uses
Classes, SysUtils, FileUtil, RTTIGrids, Forms, Controls, Graphics, ExtCtrls,
Menus, Buttons, process, SynEditKeyCmds, u_widget, u_interfaces, u_observer,
u_synmemo, u_writableComponent, u_common, u_sharedres, PropEdits,
ObjectInspector;
type
DfmtEol = (cr, lf, crlf);
DfmtIndentstyle = (tab, space);
DfmtBraceStyle = (allman, otbs, stroustrup);
DfmtConstraint = (condNewLineIndent, condNewLine, alwaysNewLine, alwaysNewLineIndent);
type
// wraps dfmt options to build the command line with ease
// and allows to save the options between session.
TDfmtWrapper = class(TWritableLfmTextComponent)
private
fEol: DfmtEol;
fTabStyle: DfmtIndentstyle;
fIndentSize: integer;
fTabWidth: integer;
fHardLLen: integer;
fSoftLLen: integer;
fBraceStyle: DfmtBraceStyle;
fSpaceCast: boolean;
fSplitOp: boolean;
fCompactLbl: boolean;
fSpaceSelImp: boolean;
fConstraints: DfmtConstraint;
procedure setSoftLLen(value: integer);
procedure setHardLLen(value: integer);
procedure setTabWidth(value: integer);
procedure setIndentSize(value: integer);
procedure setEol(value: DfmtEol);
procedure setBraceStyle(value: DfmtBraceStyle);
procedure setIndentStyle(value: DfmtIndentstyle);
procedure setConstraintsStyle(value: DfmtConstraint);
published
property endOfline: DfmtEol read fEol write setEol default lf;
property indentationStyle: DfmtIndentstyle read fTabStyle write setIndentStyle default space;
property indentSize: integer read fIndentSize write fIndentSize default 4;
property tabWidth: integer read fTabWidth write fTabWidth default 4;
property hardLineLen: integer read fHardLLen write fHardLLen default 120;
property softLineLen: integer read fSoftLLen write fSoftLLen default 80;
property braceStyle: DfmtBraceStyle read fBraceStyle write setBraceStyle default allman;
property spaceAfterCast: boolean read fSpaceCast write fSpaceCast default true;
property spaceAfterImport: boolean read fSpaceSelImp write fSpaceSelImp default true;
property splitOpAtPrevLine: boolean read fSplitOp write fSplitOp default true;
property compactLabeledStatements: boolean read fCompactLbl write fCompactLbl default true;
property constraintsStyle: DfmtConstraint read fConstraints write setConstraintsStyle default condNewLineIndent;
public
constructor create(AOwner: TComponent); override;
procedure getParameters(str: TStrings; majv, minv: Byte);
end;
{ TDfmtWidget }
TDfmtWidget = class(TDexedWidget, IDocumentObserver, ICodeFormatting)
btnApply: TSpeedButton;
btnCancel: TSpeedButton;
pnlFooter: TPanel;
dfmtOptionEditor: TTIPropertyGrid;
procedure dfmtOptionEditorEditorFilter(Sender: TObject;
aEditor: TPropertyEditor; var aShow: boolean);
private
fDoc: TDexedMemo;
fBackup: TStringList;
fDmtWrapper: TDfmtWrapper;
//
procedure docNew(document: TDexedMemo);
procedure docFocused(document: TDexedMemo);
procedure docChanged(document: TDexedMemo);
procedure docClosing(document: TDexedMemo);
//
procedure doApply(sender: TObject);
procedure doCancel(sender: TObject);
public
constructor create(aOwner: TComponent); override;
destructor destroy; override;
function singleServiceName: string;
procedure formatCurrent();
end;
implementation
{$R *.lfm}
const
optFname = 'dfmt.txt';
{$REGION Standard Comp/Obj------------------------------------------------------}
constructor TDfmtWidget.create(aOwner: TComponent);
var
fname: string;
begin
inherited;
toolbarVisible:=false;
fDmtWrapper := TDfmtWrapper.Create(self);
fBackup := TStringList.Create;
fname := getDocPath + optFname;
if fname.fileExists then
fDmtWrapper.loadFromFile(fname);
btnCancel.OnClick := @doCancel;
btnApply.OnClick := @doApply;
case GetIconScaledSize of
iss16:
begin
AssignPng(btnCancel, 'CANCEL');
AssignPng(btnApply, 'ACCEPT');
end;
iss24:
begin
AssignPng(btnCancel, 'CANCEL24');
AssignPng(btnApply, 'ACCEPT24');
end;
iss32:
begin
AssignPng(btnCancel, 'CANCEL32');
AssignPng(btnApply, 'ACCEPT32');
end;
end;
dfmtOptionEditor.TIObject := fDmtWrapper;
dfmtOptionEditor.DefaultItemHeight:=scaleY(24,96);
EntitiesConnector.addSingleService(self);
end;
destructor TDfmtWidget.destroy;
begin
dfmtOptionEditor.TIObject := nil;
fDmtWrapper.saveToFile(getDocPath + optFname);
fBackup.Free;
inherited;
end;
constructor TDfmtWrapper.create(AOwner: TComponent);
begin
inherited;
fEol := lf;
fTabStyle := DfmtIndentstyle.space;
fIndentSize := 4;
fTabWidth := 4;
fHardLLen := 120;
fSoftLLen := 80;
fBraceStyle := DfmtBraceStyle.allman;
fSpaceCast := true;
fSpaceSelImp := true;
fSplitOp := true;
fCompactLbl := true;
fConstraints := DfmtConstraint.condNewLineIndent;
end;
procedure TDfmtWidget.dfmtOptionEditorEditorFilter(Sender: TObject;
aEditor: TPropertyEditor; var aShow: boolean);
begin
case aEditor.GetName of
'Tag', 'Name': aShow := false;
else aShow := true;
end;
end;
procedure TDfmtWrapper.setSoftLLen(value: integer);
begin
if value < 60 then
value := 60
else if value > 512 then
value := 512;
fSoftLLen := value;
end;
procedure TDfmtWrapper.setHardLLen(value: integer);
begin
if value < 60 then
value := 60
else if value > 512 then
value := 512;
fHardLLen := value;
end;
procedure TDfmtWrapper.setTabWidth(value: integer);
begin
if value < 1 then
value := 1
else if value > 8 then
value := 8;
fTabWidth := value;
end;
procedure TDfmtWrapper.setIndentSize(value: integer);
begin
if value < 1 then
value := 1
else if value > 8 then
value := 8;
fIndentSize := value;
end;
procedure TDfmtWrapper.setEol(value: DfmtEol);
begin
if not (value in [DfmtEol.cr, DfmtEol.lf, DfmtEol.crlf]) then
value := DfmtEol.lf;
fEol:=value;
end;
procedure TDfmtWrapper.setBraceStyle(value: DfmtBraceStyle);
begin
if not (value in [DfmtBraceStyle.allman, DfmtBraceStyle.otbs,
DfmtBraceStyle.stroustrup]) then
value := DfmtBraceStyle.allman;
fBraceStyle:=value;
end;
procedure TDfmtWrapper.setIndentStyle(value: DfmtIndentstyle);
begin
if not (value in [DfmtIndentstyle.space, DfmtIndentstyle.tab]) then
value := DfmtIndentstyle.space;
fTabStyle:=value;
end;
procedure TDfmtWrapper.setConstraintsStyle(value: DfmtConstraint);
begin
if not (value in [DfmtConstraint.alwaysNewLine, DfmtConstraint.alwaysNewLineIndent,
DfmtConstraint.condNewLine, DfmtConstraint.condNewLineIndent]) then
value := DfmtConstraint.condNewLineIndent;
fConstraints:=value;
end;
{$ENDREGION}
{$REGION IDocumentObserver ---------------------------------------------------}
procedure TDfmtWidget.docNew(document: TDexedMemo);
begin
fDoc := document;
end;
procedure TDfmtWidget.docFocused(document: TDexedMemo);
begin
if document = fDoc then
exit;
fDoc := document;
end;
procedure TDfmtWidget.docChanged(document: TDexedMemo);
begin
end;
procedure TDfmtWidget.docClosing(document: TDexedMemo);
begin
if fDoc <> document then
exit;
fDoc := nil;
end;
{$ENDREGION}
{$REGION Dfmt things -----------------------------------------------------------}
procedure TDfmtWrapper.getParameters(str: TStrings; majv, minv: Byte);
const
eol: array[DfmtEol] of string = ('cr', 'lf', 'crlf');
falsetrue: array[boolean] of string = ('false', 'true');
idtstyle: array[DfmtIndentstyle] of string = ('tab', 'space');
brc: array[DfmtBraceStyle] of string = ('allman', 'otbs', 'stroustrup');
cts: array[DfmtConstraint] of string = ('conditional_newline_indent',
'conditional_newline', 'always_newline', 'always_newline_indent');
begin
str.Add('--end_of_line=' + eol[endOfline]);
str.Add('--max_line_length=' + intToStr(hardLineLen));
str.Add('--soft_max_line_length=' + intToStr(softLineLen));
str.Add('--indent_size=' + intToStr(indentSize));
str.Add('--indent_style=' + idtstyle[indentationStyle]);
str.Add('--tab_width=' + intToStr(tabWidth));
str.Add('--brace_style=' + brc[braceStyle]);
str.Add('--split_operator_at_line_end=' + falsetrue[splitOpAtPrevLine]);
str.Add('--space_after_cast=' + falsetrue[spaceAfterCast]);
str.Add('--selective_import_space=' + falsetrue[spaceAfterImport]);
str.Add('--compact_labeled_statements=' + falsetrue[compactLabeledStatements]);
if (majv = 0) and (minv > 4) then
str.Add('--template_constraint_style=' + cts[fConstraints]);
end;
function TDfmtWidget.singleServiceName: string;
begin
exit('ICodeFormatting');
end;
procedure TDfmtWidget.formatCurrent();
begin
doApply(self);
end;
procedure TDfmtWidget.doApply(sender: TObject);
var
inp: string;
i: integer;
prc: TProcess;
str: TStringList;
majv: byte = 0;
minv: byte = 4;
begin
if fDoc.isNotAssigned then
exit;
if not exeInSysPath('dfmt') then
exit;
fBackup.Assign(fDoc.Lines);
prc := TProcess.create(nil);
try
prc.Executable:= exeFullName('dfmt' + exeExt);
prc.Options:= prc.Options + [poUsePipes, poStderrToOutPut];
setLength(inp, 20);
prc.Parameters.Add('--version');
prc.Execute;
i := prc.Output.Read(inp[1], 20);
if (i > 4) and (inp[2] = '.') then
begin
majv := Byte(inp[1]) - Byte('0');
minv := Byte(inp[3]) - Byte('0');
end;
while prc.Running do
sleep(1);
prc.Parameters.Clear;
fDmtWrapper.getParameters(prc.Parameters, majv, minv);
prc.Execute;
inp := fDoc.Lines.Text;
prc.Input.Write(inp[1], inp.length);
prc.CloseInput;
try
str := TStringList.Create;
processOutputToStrings(prc,str);
fDoc.replaceUndoableContent(str.strictText);
except
fDoc.Lines.Assign(fBackup);
end;
while prc.Running do
sleep(1);
finally
prc.free;
str.free;
end;
end;
procedure TDfmtWidget.doCancel(sender: TObject);
begin
if fDoc.isNotAssigned then
exit;
fDoc.Lines.Assign(fBackup);
end;
{$ENDREGION}
end.