fix #280 - auto detection of indent mode + add convert dialog

This commit is contained in:
Basile Burg 2018-04-07 21:55:57 +02:00
parent 1b8a879291
commit 5936b5d760
2 changed files with 186 additions and 54 deletions

View File

@ -26,7 +26,7 @@ const
type type
TIndentationMode = (imSpaces, imTabs); TIndentationMode = (imNone, imSpaces, imTabs, imMixed);
THasMain = (mainNo, mainYes, mainDefaultBehavior); THasMain = (mainNo, mainYes, mainDefaultBehavior);
@ -299,16 +299,6 @@ type
*) *)
function globToReg(const glob: string ): string; function globToReg(const glob: string ): string;
(**
* Detects the main indentation mode used in a file
*)
function indentationMode(strings: TStrings): TIndentationMode;
(**
* Detects the main indentation mode used in a file
*)
function indentationMode(const fname: string): TIndentationMode;
(** (**
* Removes duplicate items in strings * Removes duplicate items in strings
*) *)
@ -1323,41 +1313,6 @@ begin
end; end;
end; end;
function indentationMode(strings: TStrings): TIndentationMode;
var
i: integer;
s: string;
tabs: integer = 0;
spcs: integer = 0;
begin
for s in strings do
for i := 1 to s.length do
begin
case s[i] of
#9: tabs += 1;
' ': spcs += 1;
else break;
end;
end;
if spcs >= tabs then
result := imSpaces
else
result := imTabs;
end;
function indentationMode(const fname: string): TIndentationMode;
var
str: TStringList;
begin
str := TStringList.Create;
try
str.LoadFromFile(fname);
result := indentationMode(str);
finally
str.Free;
end;
end;
function openUrl(const value: string): boolean; function openUrl(const value: string): boolean;
{$IFDEF WINDOWS} {$IFDEF WINDOWS}
function GetDefaultBrowserForCurrentUser: String; function GetDefaultBrowserForCurrentUser: String;

View File

@ -9,7 +9,7 @@ uses
SynEdit, SynPluginSyncroEdit, SynCompletion, SynEditKeyCmds, LazSynEditText, SynEdit, SynPluginSyncroEdit, SynCompletion, SynEditKeyCmds, LazSynEditText,
SynHighlighterLFM, SynEditHighlighter, SynEditMouseCmds, SynEditFoldedView, SynHighlighterLFM, SynEditHighlighter, SynEditMouseCmds, SynEditFoldedView,
SynEditMarks, SynEditTypes, SynHighlighterJScript, SynBeautifier, dialogs, SynEditMarks, SynEditTypes, SynHighlighterJScript, SynBeautifier, dialogs,
md5, md5, Spin,
//SynEditMarkupFoldColoring, //SynEditMarkupFoldColoring,
Clipbrd, fpjson, jsonparser, LazUTF8, LazUTF8Classes, Buttons, StdCtrls, Clipbrd, fpjson, jsonparser, LazUTF8, LazUTF8Classes, Buttons, StdCtrls,
ce_common, ce_writableComponent, ce_d2syn, ce_txtsyn, ce_dialogs, ce_dastworx, ce_common, ce_writableComponent, ce_d2syn, ce_txtsyn, ce_dialogs, ce_dastworx,
@ -316,6 +316,8 @@ type
procedure save; procedure save;
procedure saveTempFile; procedure saveTempFile;
// //
function indentationMode: TIndentationMode;
procedure forceIndentation(m: TIndentationMode; w: integer);
procedure addBreakPoint(line: integer); procedure addBreakPoint(line: integer);
procedure removeBreakPoint(line: integer); procedure removeBreakPoint(line: integer);
procedure curlyBraceCloseAndIndent; procedure curlyBraceCloseAndIndent;
@ -396,6 +398,14 @@ type
constructor construct(editor: TCESynMemo); constructor construct(editor: TCESynMemo);
end; end;
TMixedIndetationDialog = class(TForm)
private
class var fSpacesPerTab: integer;
procedure spinSpacesPerTabChange(sender: TObject);
public
constructor construct();
end;
procedure SetDefaultCoeditKeystrokes(ed: TSynEdit); procedure SetDefaultCoeditKeystrokes(ed: TSynEdit);
function CustomStringToCommand(const Ident: string; var Int: Longint): Boolean; function CustomStringToCommand(const Ident: string; var Int: Longint): Boolean;
@ -470,13 +480,13 @@ begin
Font.Size:= FontSize; Font.Size:= FontSize;
result := inherited CalcHintRect(MaxWidth, AHint, AData); result := inherited CalcHintRect(MaxWidth, AHint, AData);
end; end;
{$REGION TSortDialog -----------------------------------------------------------} {$REGION TSortDialog -----------------------------------------------------------}
constructor TSortDialog.construct(editor: TCESynMemo); constructor TSortDialog.construct(editor: TCESynMemo);
var var
pnl: TPanel; pnl: TPanel;
begin begin
inherited Create(nil); inherited Create(nil);
BorderStyle:= bsToolWindow;
fEditor := editor; fEditor := editor;
width := 150; width := 150;
@ -560,6 +570,64 @@ begin
end; end;
{$ENDREGION} {$ENDREGION}
{$REGION TMixedIndetationDialog}
constructor TMixedIndetationDialog.construct();
begin
inherited create(nil);
BorderStyle:= bsToolWindow;
caption := 'Indentation converter';
Position:= TPosition.poMainFormCenter;
fSpacesPerTab := 4;
with TButton.Create(self) do
begin
Align:= alBottom;
parent := self;
caption := 'Do nothing';
AutoSize:= true;
ModalResult:= 1;
BorderSpacing.Around:=4;
end;
with TSpinEdit.Create(self) do
begin
value := fSpacesPerTab;
Align:= alTop;
parent := self;
Caption := 'Spaces per TAB';
MinValue:= 1;
MaxValue:= 8;
BorderSpacing.Around:=4;
OnChange:= @spinSpacesPerTabChange;
hint := 'defines how many spaces per TAB will be used';
ShowHint:=true;
end;
with TButton.Create(self) do
begin
Align:= alTop;
parent := self;
caption := 'Always use tabs';
AutoSize:= true;
ModalResult:= 10;
BorderSpacing.Around:=4;
end;
with TButton.Create(self) do
begin
Align:= alTop;
parent := self;
caption := 'Always use spaces';
AutoSize:= true;
ModalResult:= 11;
BorderSpacing.Around:=4;
end;
width := ScaleX(280, 96);
height := ScaleY(150, 96);
end;
procedure TMixedIndetationDialog.spinSpacesPerTabChange(sender: TObject);
begin
self.fSpacesPerTab:= TSpinEdit(sender).Value;
end;
{$ENDREGION}
{$REGION TCESynMemoCache -------------------------------------------------------} {$REGION TCESynMemoCache -------------------------------------------------------}
constructor TCESynMemoCache.create(aComponent: TComponent); constructor TCESynMemoCache.create(aComponent: TComponent);
begin begin
@ -1374,6 +1442,93 @@ begin
end; end;
end; end;
function TCESynMemo.indentationMode: TIndentationMode;
function checkLine(index: integer): TIndentationMode;
var
u: string;
begin
result := imNone;
u := Lines[index];
if (u.length > 0) and (u[1] = #9) then
result := imTabs
else if (u.length > 1) and (u[1..2] = ' ') then
result := imSpaces;
end;
var
i: integer;
t: integer = 0;
s: integer = 0;
begin
for i:= 0 to lines.count-1 do
begin
result := checkLine(i);
t += byte(result = imTabs);
s += byte(result = imSpaces);
end;
if (t <> 0) and (s <> 0) then
result := imMixed
else if t = 0 then
result := imSpaces
else if s = 0 then
result := imTabs
else
result := imNone;
end;
procedure TCESynMemo.forceIndentation(m: TIndentationMode; w: integer);
var
s: string;
i: integer;
p: integer;
c: integer;
b: string;
begin
for i:= 0 to lines.Count-1 do
begin
c := 0;
p := 1;
s := lines.Strings[i];
case m of
imTabs:
begin
while p <= s.length do
begin
if s[p] = ' ' then
c+=1
else break;
p += 1;
end;
if c >= w then
begin
setLength(b, c div w);
FillChar(b[1], b.length, #9);
s := b + s[c+1 .. s.length];
lines[i] := s;
fModified:=true;
end;
end;
imSpaces:
begin
while p <= s.length do
begin
if s[p] = #9 then
c+=1
else break;
p += 1;
end;
if c > 0 then
begin
setLength(b, c * w);
FillChar(b[1], b.length, ' ');
s := b + s[c+1 .. s.length];
lines[i] := s;
fModified:=true;
end;
end;
end;
end;
end;
procedure TCESynMemo.insertLeadingDDocSymbol(c: char); procedure TCESynMemo.insertLeadingDDocSymbol(c: char);
begin begin
BeginUndoBlock; BeginUndoBlock;
@ -2853,12 +3008,34 @@ begin
loadCache; loadCache;
fCacheLoaded := true; fCacheLoaded := true;
end; end;
if detectIndentMode then case indentationMode() of
begin imTabs:
case indentationMode(lines) of if detectIndentMode then
imTabs: Options:= Options - [eoTabsToSpaces]; Options:= Options - [eoTabsToSpaces];
imSpaces: Options:= Options + [eoTabsToSpaces]; imSpaces:
end; if detectIndentMode then
Options:= Options + [eoTabsToSpaces];
imMixed:
if (isDSource or alwaysAdvancedFeatures) and
(dlgYesNo('Mixed indentation style detected, ' +
'do you wish to convert to a single mode ?') = mrYes) then
with TMixedIndetationDialog.construct() do
try
case ShowModal of
10:
begin
forceIndentation(imTabs, TMixedIndetationDialog.fSpacesPerTab);
Options:= Options - [eoTabsToSpaces];
end;
11:
begin
forceIndentation(imSpaces, TMixedIndetationDialog.fSpacesPerTab);
Options:= Options + [eoTabsToSpaces];
end;
end;
finally
free;
end;
end; end;
subjDocChanged(TCEMultiDocSubject(fMultiDocSubject), self); subjDocChanged(TCEMultiDocSubject(fMultiDocSubject), self);
fCanDscan := true; fCanDscan := true;