mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-05-10 15:42:47 +02:00
443 lines
10 KiB
ObjectPascal
443 lines
10 KiB
ObjectPascal
unit SortUsesData;
|
|
{(*}
|
|
(*------------------------------------------------------------------------------
|
|
Delphi Code formatter source code
|
|
|
|
The Original Code is SortUsesData.pas, released September 2004.
|
|
The Initial Developer of the Original Code is Anthony Steele.
|
|
Portions created by Anthony Steele are Copyright (C) 1999-2008 Anthony Steele.
|
|
All Rights Reserved.
|
|
Contributor(s): Anthony Steele.
|
|
|
|
The contents of this file are subject to the Mozilla Public License Version 1.1
|
|
(the "License"). you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at http://www.mozilla.org/NPL/
|
|
|
|
Software distributed under the License is distributed on an "AS IS" basis,
|
|
WITHOUT WARRANTY OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing rights and limitations
|
|
under the License.
|
|
|
|
Alternatively, the contents of this file may be used under the terms of
|
|
the GNU General Public License Version 2 or later (the "GPL")
|
|
See http://www.gnu.org/licenses/gpl.html
|
|
------------------------------------------------------------------------------*)
|
|
{*)}
|
|
|
|
{$I JcfGlobal.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
{ delphi }
|
|
Contnrs, Classes,
|
|
{ local }
|
|
SourceToken, ParseTreeNode;
|
|
|
|
{ some classes used in sorting a uses clause }
|
|
|
|
type
|
|
{ stores a uses unit name and some trailing tokens }
|
|
TUsesItem = class(TObject)
|
|
private
|
|
fcItems: TObjectList;
|
|
|
|
function GetItem(const piIndex: integer): TSourceToken;
|
|
|
|
public
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
|
|
function Count: integer;
|
|
function SortKey: string;
|
|
function Text: string;
|
|
function IndentifierIndex: integer;
|
|
|
|
procedure Add(const pcItem: TSourceToken);
|
|
procedure AttachTo(const pcNode: TParseTreeNode; const pbAllowCommaFirst: boolean);
|
|
|
|
property Items[const piIndex: integer]: TSourceToken read GetItem;
|
|
end;
|
|
|
|
{ a section is one of two things
|
|
- It is a list of uses items, to be sorted
|
|
- breaking tokens between these lists. Not sorted }
|
|
TUsesSection = class(TObject)
|
|
private
|
|
fbSorted: boolean;
|
|
fcItems: TObjectList;
|
|
|
|
function GetItem(const piIndex: integer): TUsesItem;
|
|
public
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
|
|
function Count: integer;
|
|
function Text: string;
|
|
|
|
procedure Sort(Compare: TListSortCompare);
|
|
|
|
procedure AddUsesItem;
|
|
procedure AddToken(const pcItem: TSourceToken);
|
|
procedure AttachTo(const pcNode: TParseTreeNode; pbAllowCommaFirst: boolean);
|
|
|
|
property Sorted: boolean read fbSorted write fbSorted;
|
|
|
|
property Items[const piIndex: integer]: TUsesItem read GetItem;
|
|
end;
|
|
|
|
function AlphaNameSort(Item1, Item2: Pointer): integer;
|
|
function ReverseAlphaNameSort(Item1, Item2: Pointer): integer;
|
|
function LengthNameSort(Item1, Item2: Pointer): integer;
|
|
function ReverseLengthNameSort(Item1, Item2: Pointer): integer;
|
|
|
|
|
|
implementation
|
|
|
|
uses
|
|
{ delphi }
|
|
{$IFNDEF FPC}Windows,{$ENDIF} Math, SysUtils,
|
|
{local }
|
|
ParseTreeNodeType, Tokens, TokenUtils;
|
|
|
|
function AlphaNameSort(Item1, Item2: Pointer): integer;
|
|
var
|
|
lcItem1, lcItem2: TUsesItem;
|
|
begin
|
|
lcItem1 := TUsesItem(Item1);
|
|
lcItem2 := TUsesItem(Item2);
|
|
|
|
if lcItem1 = nil then
|
|
Result := -1
|
|
else if lcItem2 = nil then
|
|
Result := 1
|
|
else
|
|
begin
|
|
Result := AnsiCompareText(lcItem1.SortKey, lcItem2.SortKey);
|
|
end;
|
|
end;
|
|
|
|
function ReverseAlphaNameSort(Item1, Item2: Pointer): integer;
|
|
begin
|
|
Result := AlphaNameSort(Item1, Item2) * -1;
|
|
end;
|
|
|
|
function LengthNameSort(Item1, Item2: Pointer): integer;
|
|
var
|
|
lcItem1, lcItem2: TUsesItem;
|
|
begin
|
|
lcItem1 := TUsesItem(Item1);
|
|
lcItem2 := TUsesItem(Item2);
|
|
|
|
if lcItem1 = nil then
|
|
Result := -1
|
|
else if lcItem2 = nil then
|
|
Result := 1
|
|
else
|
|
begin
|
|
Result := Sign(Length(lcItem1.SortKey) - Length(lcItem2.SortKey));
|
|
|
|
{ Length has more sort collisions that alphabetic
|
|
same length -> Alphabetic sort }
|
|
if Result = 0 then
|
|
Result := AnsiCompareText(lcItem1.SortKey, lcItem2.SortKey);
|
|
end;
|
|
end;
|
|
|
|
function ReverseLengthNameSort(Item1, Item2: Pointer): integer;
|
|
var
|
|
lcItem1, lcItem2: TUsesItem;
|
|
begin
|
|
lcItem1 := TUsesItem(Item1);
|
|
lcItem2 := TUsesItem(Item2);
|
|
|
|
if lcItem1 = nil then
|
|
Result := -1
|
|
else if lcItem2 = nil then
|
|
Result := 1
|
|
else
|
|
begin
|
|
Result := Sign(Length(lcItem2.SortKey) - Length(lcItem1.SortKey));
|
|
|
|
{ Soting the other way by length, but still forwards alphbetically }
|
|
if Result = 0 then
|
|
Result := AnsiCompareText(lcItem1.SortKey, lcItem2.SortKey);
|
|
end;
|
|
end;
|
|
|
|
|
|
{-------------------------------------------------------------------------------
|
|
TUsesItem }
|
|
|
|
|
|
constructor TUsesItem.Create;
|
|
begin
|
|
inherited;
|
|
fcItems := TObjectList.Create;
|
|
// tokens are just referred here, owned by the parse treee
|
|
fcItems.OwnsObjects := False;
|
|
end;
|
|
|
|
destructor TUsesItem.Destroy;
|
|
begin
|
|
FreeAndNil(fcItems);
|
|
inherited;
|
|
end;
|
|
procedure TUsesItem.Add(const pcItem: TSourceToken);
|
|
begin
|
|
fcItems.Add(pcItem);
|
|
end;
|
|
|
|
function TUsesItem.Count: integer;
|
|
begin
|
|
Result := fcItems.Count;
|
|
end;
|
|
|
|
function TUsesItem.GetItem(const piIndex: integer): TSourceToken;
|
|
begin
|
|
Result := TSourceToken(fcItems[piIndex]);
|
|
end;
|
|
|
|
function TUsesItem.SortKey: string;
|
|
var
|
|
liLoop: integer;
|
|
lcTest: TSourceToken;
|
|
begin
|
|
Result := '';
|
|
|
|
// find the identifiers
|
|
for liLoop := 0 to Count - 1 do
|
|
begin
|
|
lcTest := Items[liLoop];
|
|
if lcTest.TokenType in [ttIdentifier, ttDot] then
|
|
begin
|
|
Result := Result + lcTest.SourceCode;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TUsesItem.Text: string;
|
|
var
|
|
liLoop: integer;
|
|
lcTest: TSourceToken;
|
|
begin
|
|
Result := '';
|
|
|
|
for liLoop := 0 to Count - 1 do
|
|
begin
|
|
lcTest := Items[liLoop];
|
|
Result := Result + lcTest.SourceCode;
|
|
end;
|
|
end;
|
|
|
|
|
|
function TUsesItem.IndentifierIndex: integer;
|
|
var
|
|
liLoop: integer;
|
|
lcTest: TSourceToken;
|
|
begin
|
|
Result := -1;
|
|
|
|
// find the first identifier
|
|
for liLoop := 0 to Count - 1 do
|
|
begin
|
|
lcTest := Items[liLoop];
|
|
if lcTest.TokenType = ttIdentifier then
|
|
begin
|
|
Result := liLoop;
|
|
break;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TUsesItem.AttachTo(const pcNode: TParseTreeNode; const pbAllowCommaFirst: boolean);
|
|
var
|
|
lbHasSolid: boolean;
|
|
|
|
procedure AddToken(const pcToken: TSourceToken);
|
|
begin
|
|
// skip the comma if it's the first token and asked to do so
|
|
if (not lbHasSolid) and (not pbAllowCommaFirst) and
|
|
(pcToken.TokenType = ttComma) then
|
|
exit;
|
|
|
|
if (not lbHasSolid) and pcToken.IsSolid then
|
|
lbHasSolid := True;
|
|
|
|
pcNode.AddChild(pcToken);
|
|
end;
|
|
|
|
var
|
|
liIndentifierIndex: integer;
|
|
lcUsesItem: TParseTreeNode;
|
|
lcIdent: TParseTreeNode;
|
|
lcToken: TSourceToken;
|
|
liloop: integer;
|
|
lbHasComma: Boolean;
|
|
lcComma: TSourceToken;
|
|
lsFileName: string;
|
|
|
|
begin
|
|
if Count < 1 then
|
|
exit;
|
|
|
|
Assert(pcNode <> nil);
|
|
liIndentifierIndex := IndentifierIndex;
|
|
lbHasSolid := False;
|
|
lsFileName := '';
|
|
|
|
if liIndentifierIndex < 0 then
|
|
begin
|
|
for liLoop := 0 to Count - 1 do
|
|
begin
|
|
lcToken := Items[liLoop];
|
|
lsFileName := lcToken.FileName;
|
|
AddToken(lcToken);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
for liLoop := 0 to liIndentifierIndex - 1 do
|
|
begin
|
|
lcToken := Items[liLoop];
|
|
lsFileName := lcToken.FileName;
|
|
AddToken(lcToken);
|
|
end;
|
|
|
|
// attach the data back onto the parent node, a uses clause
|
|
lbHasSolid := True;
|
|
lcUsesItem := TParseTreeNode.Create;
|
|
lcUsesItem.NodeType := nUsesItem;
|
|
|
|
pcNode.AddChild(lcUsesItem);
|
|
|
|
lcIdent := TParseTreeNode.Create;
|
|
lcIdent.NodeType := nUsesItem;
|
|
|
|
lcUsesItem.AddChild(lcIdent);
|
|
|
|
// add the identifier and trailing tokens
|
|
lcIdent.AddChild(Items[liIndentifierIndex]);
|
|
|
|
// add trailing tokens
|
|
lbHasComma := False;
|
|
for liLoop := liIndentifierIndex + 1 to Count - 1 do
|
|
begin
|
|
lcToken := Items[liLoop];
|
|
if lcToken.TokenType = ttComma then
|
|
lbHasComma := True;
|
|
AddToken(lcToken);
|
|
end;
|
|
|
|
{ needs to end with a comma }
|
|
if not lbHasComma then
|
|
begin
|
|
lcComma := TSourceToken.Create;
|
|
lcComma.FileName := lsFileName;
|
|
|
|
lcComma.SourceCode := ',';
|
|
lcComma.TokenType := ttComma;
|
|
|
|
AddToken(lcComma);
|
|
|
|
AddToken(NewSpace(1));
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
{------------------------------------------------------------------------------
|
|
TUsesSection }
|
|
|
|
constructor TUsesSection.Create;
|
|
begin
|
|
inherited;
|
|
fcItems := TObjectList.Create;
|
|
// tokens are just referred here, owned by the parse treee
|
|
fcItems.OwnsObjects := False;
|
|
end;
|
|
|
|
destructor TUsesSection.Destroy;
|
|
begin
|
|
FreeAndNil(fcItems);
|
|
inherited;
|
|
end;
|
|
|
|
procedure TUsesSection.AddUsesItem;
|
|
var
|
|
lcNewItem: TUsesItem;
|
|
begin
|
|
lcNewItem := TUsesItem.Create;
|
|
fcItems.Add(lcNewItem);
|
|
end;
|
|
|
|
function TUsesSection.Count: integer;
|
|
begin
|
|
Result := fcItems.Count;
|
|
end;
|
|
|
|
function TUsesSection.GetItem(const piIndex: integer): TUsesItem;
|
|
begin
|
|
Result := TUsesItem(fcItems.Items[piIndex]);
|
|
end;
|
|
|
|
procedure TUsesSection.AddToken(const pcItem: TSourceToken);
|
|
begin
|
|
if Count = 0 then
|
|
AddUsesItem;
|
|
|
|
// add to the last uses item
|
|
Items[Count - 1].Add(pcItem);
|
|
end;
|
|
|
|
|
|
procedure TUsesSection.Sort(Compare: TListSortCompare);
|
|
begin
|
|
if Sorted then
|
|
fcItems.Sort(Compare);
|
|
end;
|
|
|
|
function TUsesSection.Text: string;
|
|
var
|
|
liItemLoop: integer;
|
|
lcItem: TusesItem;
|
|
begin
|
|
Result := '';
|
|
|
|
for liItemLoop := 0 to Count - 1 do
|
|
begin
|
|
lcItem := Items[liItemLoop];
|
|
Result := Result + lcItem.Text;
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure TUsesSection.AttachTo(const pcNode: TParseTreeNode; pbAllowCommaFirst: boolean);
|
|
var
|
|
liItemLoop: integer;
|
|
lcItem: TusesItem;
|
|
lcLastToken, lcNextToken: TSourceToken;
|
|
begin
|
|
for liItemLoop := 0 to Count - 1 do
|
|
begin
|
|
lcItem := Items[liItemLoop];
|
|
lcItem.AttachTo(pcNode, pbAllowCommaFirst);
|
|
pbAllowCommaFirst := True; // set true fater first one
|
|
|
|
// space it?
|
|
if Sorted and (liItemLoop < (Count - 1)) and (lcItem.Count > 0) then
|
|
begin
|
|
lcLastToken := lcItem.Items[lcItem.Count - 1];
|
|
if lcLastToken.TokenType = ttComma then
|
|
begin
|
|
lcNextToken := Items[liItemLoop + 1].Items[0];
|
|
|
|
if lcNextToken.IsSolid then
|
|
pcNode.AddChild(NewSpace(1));
|
|
end;
|
|
end;
|
|
end
|
|
end;
|
|
|
|
end.
|