amxmodx/editor/studio/UnitCodeInspector.pas
Christian Hammacher 7c21deb0f2 Fixed memory leak
Updated Modified-Event (now only one parameter [the modified text])
2005-09-07 22:20:28 +00:00

427 lines
14 KiB
ObjectPascal
Executable File

unit UnitCodeInspector;
interface
uses SysUtils, Classes, Windows, JvInspector, UnitMainTools, Contnrs;
type
TSelectionTextList = class(TStringList)
private
FSelected: Integer;
function GetSelectedText: string;
function GetSelected: Integer;
procedure SetSelectedText(const Value: string);
procedure SetSelected(const Value: Integer);
public
property Selected: Integer read GetSelected write SetSelected;
property SelectedText: string read GetSelectedText write SetSelectedText;
end;
TJvInspectorSelectionTextListItem = class(TJvCustomInspectorItem)
protected
function GetDisplayValue: string; override;
procedure GetValueList(const Strings: TStrings); override;
procedure SetDisplayValue(const Value: string); override;
procedure SetFlags(const Value: TInspectorItemFlags); override;
end;
TStringWrapper = class(TObject)
public
Value: string;
constructor Create(const AValue: string); reintroduce;
end;
TSTLWrapper = class(TObject)
public
STL: TSelectionTextList;
Value: String;
constructor Create(const ASTL: TSelectionTextList; const AValue: String); reintroduce;
destructor Destroy; reintroduce;
end;
function AddField(eName, eCategory, eValue: String): TJvCustomInspectorItem;
function AddCombo(eName, eCategory, eValue: String; eValues: array of string): TJvCustomInspectorItem;
procedure UpdateCI;
procedure UpdateCI_Pawn;
var eFormatSettings: String;
eAllIncluded: TStringArray;
FItems: TObjectList;
STLItem: TSelectionTextList;
implementation
uses UnitfrmMain, UnitLanguages, UnitCodeUtils, UnitMenuGenerators,
UnitPlugins;
var eBraceTexts: TStringList;
{ "Combobox"-Item }
function TSelectionTextList.GetSelected: Integer;
begin
if FSelected < -1 then
FSelected := -1
else if FSelected >= Count then
FSelected := Count - 1;
Result := FSelected;
end;
function TSelectionTextList.GetSelectedText: string;
begin
if Selected >= 0 then
Result := Strings[Selected]
else
Result := '';
end;
procedure TSelectionTextList.SetSelected(const Value: Integer);
begin
FSelected := Value;
GetSelected; // adjust FSelected
end;
procedure TSelectionTextList.SetSelectedText(const Value: string);
begin
FSelected := IndexOf(Value);
end;
function TJvInspectorSelectionTextListItem.GetDisplayValue: string;
begin
Result := TSelectionTextList(Data.AsOrdinal).SelectedText;
end;
procedure TJvInspectorSelectionTextListItem.GetValueList(const Strings: TStrings);
begin
Strings.Assign(TSelectionTextList(Data.AsOrdinal));
end;
procedure TJvInspectorSelectionTextListItem.SetDisplayValue(const Value: string);
begin
TSelectionTextList(Data.AsOrdinal).SelectedText := Value;
end;
procedure TJvInspectorSelectionTextListItem.SetFlags(const Value: TInspectorItemFlags);
begin
inherited SetFlags(Value + [iifValueList]);
end;
constructor TStringWrapper.Create(const AValue: string);
begin
inherited Create;
Value := AValue;
end;
{ Codeinspector Add Functions }
function AddCombo(eName, eCategory, eValue: String; eValues: array of string): TJvCustomInspectorItem;
var
i: integer;
eParent: TJvCustomInspectorItem;
Item: TSTLWrapper;
Found: Boolean;
begin
eParent := nil;
for i := 0 to frmMain.jviCode.Root.Count -1 do
begin
if (frmMain.jviCode.Root.Items[i].DisplayName = eCategory) and (frmMain.jviCode.Root.Items[i] is TJvInspectorCustomCategoryItem) then
begin
eParent := frmMain.jviCode.Root.Items[i];
Break;
end;
end;
if eParent = nil then
begin
eParent := TJvInspectorCustomCategoryItem.Create(frmMain.jviCode.Root, nil);
eParent.DisplayName := eCategory;
end;
if eName <> '' then
begin
STLItem := TSelectionTextList.Create;
Found := False;
for i := 0 to High(eValues) do begin
STLItem.Add(eValues[i]);
if eValues[i] = eValue then
Found := True;
end;
if not Found then begin
STLItem.Add(eValue);
STLItem.Sort;
end;
Item := TSTLWrapper.Create(STLItem, eValue);
FItems.Add(Item);
FItems.Add(STLItem);
STLItem.SelectedText := Item.Value;
Result := TJvInspectorVarData.New(eParent, eName, TypeInfo(TSelectionTextList), @Item.STL);
frmMain.jviCode.Root.Sort;
eParent.Expanded := True;
end
else
begin
Result := nil;
frmMain.jviCode.Root.Sort;
end;
end;
function AddField(eName, eCategory, eValue: String): TJvCustomInspectorItem;
var
i: integer;
eParent: TJvCustomInspectorItem;
Item: TStringWrapper;
begin
eParent := nil;
for i := 0 to frmMain.jviCode.Root.Count -1 do
begin
if (frmMain.jviCode.Root.Items[i].DisplayName = eCategory) and (frmMain.jviCode.Root.Items[i] is TJvInspectorCustomCategoryItem) then
begin
eParent := frmMain.jviCode.Root.Items[i];
Break;
end;
end;
if eParent = nil then
begin
eParent := TJvInspectorCustomCategoryItem.Create(frmMain.jviCode.Root, nil);
eParent.DisplayName := eCategory;
end;
if eName <> '' then
begin
Item := TStringWrapper.Create(eValue); // StringWrapper erzeugen, damit der String erhalten bleibt
FItems.Add(Item); // und das Item in die Liste eintragen, damit kein Speicherleck entsteht
Result := TJvInspectorVarData.New(eParent, eName, TypeInfo(String), @Item.Value);
frmMain.jviCode.Root.Sort;
eParent.Expanded := True;
end
else
begin
Result := nil;
frmMain.jviCode.Root.Sort;
end;
end;
{ Parse Functions }
procedure UpdateCI;
begin
if not Plugin_UpdateCodeInspector(GetCurrLang.Name, ActiveDoc.FileName, frmMain.tsMain.Items[frmMain.tsMain.ActiveTabIndex].Caption, True) then exit;
if GetCurrLang.Name = 'Pawn' then begin
UpdateCI_Pawn;
Plugin_UpdateCodeInspector(GetCurrLang.Name, ActiveDoc.FileName, frmMain.tsMain.Items[frmMain.tsMain.ActiveTabIndex].Caption, False);
end;
end;
procedure UpdateCI_Pawn;
procedure HideBracesAndStrings(var eStr: String);
begin
while Between(eStr, '{', '}') <> '' do begin
eBraceTexts.Add('{' + Between(eStr, '{', '}') + '}');
eStr := StringReplace(eStr, '{' + Between(eStr, '{', '}') + '}', #1 + IntToStr(eBraceTexts.Count) + #1, []);
end;
while CountChars(eStr, '"') > 1 do begin
eBraceTexts.Add('"' + StringReplace(Between(eStr, '"', '"'), ':', #3, [rfReplaceAll]) + '"');
eStr := StringReplace(eStr, '"' + Between(eStr, '"', '"') + '"', #2 + IntToStr(eBraceTexts.Count) + #2, []);
end;
end;
function ShowBracesAndStrings(eStr: String): String;
var k: integer;
begin
while Between(eStr, #1, #1) <> '' do begin
k := StrToInt(Between(eStr, #1, #1));
eStr := StringReplace(eStr, #1 + IntToStr(k) + #1, eBraceTexts[k -1], []);
end;
while Between(eStr, #2, #2) <> '' do begin
k := StrToInt(Between(eStr, #2, #2));
eStr := StringReplace(eStr, #2 + IntToStr(k) + #2, eBraceTexts[k -1], []);
end;
Result := eStr;
end;
var eCurrLine, eBackupLine: String;
i, k: integer;
eStr: TStringList;
eVars, eConsts: Integer;
eVarName, eVarType, eVarValue: String;
begin
eBackupLine := frmMain.sciEditor.Lines[frmMain.sciEditor.GetCurrentLineNumber];
eCurrLine := Trim(StringReplace(eBackupLine, #9, #32, [rfReplaceAll]));
eCurrLine := RemoveStringsAndComments(eCurrLine, False);
eAllIncluded := GetAllIncludeFiles;
eStr := TStringList.Create;
eBraceTexts := TStringList.Create;
eVars := 0;
eConsts := 0;
frmMain.jviCode.Clear;
FItems.Clear;
eFormatSettings := '';
{ Constants and Variables }
if (IsAtStart('new', eCurrLine, False)) then begin // const or variable
Delete(eCurrLine, 1, 4);
// done? okay, split all items if there are more than one; and if not, it's okay...
HideBracesAndStrings(eCurrLine);
eStr.Text := StringReplace(eCurrLine, ',', #13, [rfReplaceAll]);
for i := 0 to eStr.Count - 1 do begin
eStr[i] := ShowBracesAndStrings(eStr[i]);
eVarType := '';
eVarValue := '';
if (Trim(eStr[i]) <> '') then begin
eVarName := Trim(RemoveSemicolon(eStr[i]));
if Pos(':', eVarName) <> 0 then begin
eVarType := Trim(Copy(eVarName, 1, Pos(':', eVarName) -1));
eVarName := Trim(Copy(eVarName, Pos(':', eVarName) +1, Length(eVarName)));
end;
if Pos('=', eVarName) <> 0 then begin // constant
Inc(eConsts, 1);
eFormatSettings := eFormatSettings + '-Constant ' + IntToStr(eConsts) + '-';
eVarValue := Trim(Copy(eVarName, Pos('=', eVarName) +1, Length(eVarName)));
eVarValue := StringReplace(eVarValue, #3, ':', [rfReplaceAll]);
eVarName := Trim(Copy(eVarName, 1, Pos('=', eVarName) -1));
AddField(lName, 'Constant ' + IntToStr(eConsts), eVarName);
if eVarType <> '' then
AddField(lType, 'Constant ' + IntToStr(eConsts), eVarType);
if eVarValue <> '' then
AddField(lValue, 'Constant ' + IntToStr(eConsts), eVarValue);
end
else begin // variable
Inc(eVars, 1);
eFormatSettings := eFormatSettings + '-Variable ' + IntToStr(eVars) + '-';
AddField(lName, 'Variable ' + IntToStr(eVars), eVarName);
if eVarType <> '' then
AddField(lType, 'Variable ' + IntToStr(eVars), eVarType);
end;
end;
end;
if frmMain.jviCode.Root.Count = 1 then
frmMain.jviCode.Root.Items[0].DisplayName := Copy(frmMain.jviCode.Root.Items[0].DisplayName, 1, Length(frmMain.jviCode.Root.Items[0].DisplayName) -2);
end
{ Conditions }
else if (IsAtStart('if', eCurrLine, False)) then begin
if (CountChars(eCurrLine, '(') = CountChars(eCurrLine, ')')) and (CountChars(eCurrLine, '(') <> 0) then begin
eCurrLine := Copy(eCurrLine, 1, GetMatchingBrace(eCurrLine) -1);
eCurrLine := Copy(eCurrLine, Pos('(', eCurrLine) +1, Length(eCurrLine));
eFormatSettings := StringReplace(eBackupLine, '(' + eCurrLine + ')', #1#3#3#7, []);
HideBracesAndStrings(eCurrLine);
eStr.Text := StringReplace(eCurrLine, '||', #13, [rfReplaceAll]);
k := eStr.Count -1; // from 0 to k -> OR operators
eStr.Text := StringReplace(eStr.Text, '&&', #13, [rfReplaceAll]);
for i := 0 to eStr.Count -1 do begin
eStr[i] := Trim(ShowBracesAndStrings(eStr[i]));
if (Pos('(', eStr[i]) = 1) and (Pos(')', eStr[i]) = Length(eStr[i])) then
eStr[i] := Copy(Copy(eStr[i], 2, Length(eStr[i])), 1, Length(eStr[i]) -1);
if eStr.Count = 1 then
eCurrLine := 'If-Condition'
else
eCurrLine := 'If-Condition ' + IntToStr(frmMain.jviCode.Root.Count +1);
if i <> eStr.Count -1 then begin
if i < k then
AddCombo('Operator', eCurrLine, '||', ['||', '&&'])
else
AddCombo('Operator', eCurrLine, '&&', ['||', '&&']);
end;
AddField('Condition', eCurrLine, eStr[i]);
end;
end
else
AddField('', 'Invalid condition', '');
end
{ Defined }
else if (IsAtStart('#define', eCurrLine, False)) then begin
eCurrLine := Trim(Copy(eCurrLine, 8, Length(eCurrLine)));
HideBracesAndStrings(eCurrLine);
eCurrLine := StringReplace(eCurrLine, #9, #32, [rfReplaceAll]);
eCurrLine := ShowBracesAndStrings(eCurrLine);
AddField('Name', 'Defined', Copy(eCurrLine, 1, Pos(#32, eCurrLine) -1));
eCurrLine := Trim(Copy(eCurrLine, Pos(#32, eCurrLine) +1, Length(eCurrLine)));
AddField('Value', 'Defined', eCurrLine);
end
{ Included }
else if (IsAtStart('#include', eCurrLine, False)) then begin
eCurrLine := Trim(StringReplace(eCurrLine, #9, #32, [rfReplaceAll]));
if Between(eCurrLine, '<', '>') <> '' then begin
eCurrLine := Between(eCurrLine, '<', '>');
eFormatSettings := StringReplace(eBackupLine, '<' + eCurrLine + '>', '<-Filename->', []);
end
else if Between(eCurrLine, '"', '"') <> '' then begin
eCurrLine := Between(eCurrLine, '"', '"');
eFormatSettings := StringReplace(eBackupLine, '"' + eCurrLine + '"', '"-Filename-"', []);
end
else begin
eCurrLine := Copy(eCurrLine, 9, Length(eCurrLine));
eFormatSettings := '#include -Filename-';
end;
eCurrLine := Trim(eCurrLine);
AddCombo('File', 'Included', eCurrLine, eAllIncluded);
end
{ Assignments }
else begin
if (Pos('=', eCurrLine) <> 0) then begin
eCurrLine := Trim(eCurrLine);
while Pos(eCurrLine[1], frmMain.sciEditor.WordChars + '[]') <> 0 do
Delete(eCurrLine, 1, 1);
eCurrLine := Trim(eCurrLine);
if Pos('=', eCurrLine) <= 2 then begin
while (Pos(Copy(eCurrLine, 1, 1), frmMain.sciEditor.WordChars + #32 + #9) = 0) and (Length(eCurrLine) <> 0) do begin
eFormatSettings := eFormatSettings + eCurrLine[1];
Delete(eCurrLine, 1, 1);
end;
eCurrLine := RemoveSemicolon(Trim(eBackupLine));
eCurrLine := StringReplace(eCurrLine, #9, #32, [rfReplaceAll]);
AddField('a', 'Assignment', Copy(eCurrLine, 1, Pos(eFormatSettings, eCurrLine) - Length(eFormatSettings)));
AddField('b', 'Assignment', Trim(Copy(eCurrLine, Pos(eFormatSettings, eCurrLine) + Length(eFormatSettings), Length(eCurrLine))));
AddField('Operator', 'Assignment', eFormatSettings);
end
else
AddField('', 'No information available.', '');
end
else
AddField('', 'No information available.', '');
end;
eBraceTexts.Free;
SetLength(eAllIncluded, 0);
eStr.Free;
end;
{ TSTLWrapper }
constructor TSTLWrapper.Create(const ASTL: TSelectionTextList;
const AValue: String);
begin
STL := ASTL;
Value := AValue;
inherited Create;
end;
destructor TSTLWrapper.Destroy;
begin
STL.Free;
inherited;
end;
initialization
FItems := TObjectList.Create;
finalization
FItems.Free;
end.