MG: improved code completion: special proc bodies

git-svn-id: trunk@1520 -
This commit is contained in:
lazarus 2002-03-15 14:50:36 +00:00
parent bee2a144d9
commit 274decf5f1
2 changed files with 76 additions and 43 deletions

View File

@ -51,16 +51,17 @@ type
TCodeCompletionCodeTool = class(TEventsCodeTool) TCodeCompletionCodeTool = class(TEventsCodeTool)
private private
ClassNode, StartNode: TCodeTreeNode;
FirstInsert: TCodeTreeNodeExtension;
JumpToProcName: string;
ASourceChangeCache: TSourceChangeCache; ASourceChangeCache: TSourceChangeCache;
NewPrivatSectionIndent, NewPrivatSectionInsertPos: integer; ClassNode, StartNode: TCodeTreeNode;
FCompleteProperties: boolean;
FirstInsert: TCodeTreeNodeExtension;
FSetPropertyVariablename: string; FSetPropertyVariablename: string;
JumpToProcName: string;
NewPrivatSectionIndent, NewPrivatSectionInsertPos: integer;
function ProcExists(const NameAndParams: string): boolean; function ProcExists(const NameAndParams: string): boolean;
function VarExists(const UpperName: string): boolean; function VarExists(const UpperName: string): boolean;
procedure AddInsert(PosNode: TCodeTreeNode; procedure AddInsert(PosNode: TCodeTreeNode;
const CleanDef, Def, IdentifierName: string); const CleanDef, Def, IdentifierName, Body: string);
function NodeExtIsVariable(ANodeExt: TCodeTreeNodeExtension): boolean; function NodeExtIsVariable(ANodeExt: TCodeTreeNodeExtension): boolean;
function CompleteProperty(PropNode: TCodeTreeNode): boolean; function CompleteProperty(PropNode: TCodeTreeNode): boolean;
procedure InsertNewClassParts(PartType: NewClassPart); procedure InsertNewClassParts(PartType: NewClassPart);
@ -73,6 +74,8 @@ type
constructor Create; constructor Create;
property SetPropertyVariablename: string property SetPropertyVariablename: string
read FSetPropertyVariablename write FSetPropertyVariablename; read FSetPropertyVariablename write FSetPropertyVariablename;
property CompleteProperties: boolean
read FCompleteProperties write FCompleteProperties;
end; end;
@ -126,7 +129,7 @@ begin
end; end;
procedure TCodeCompletionCodeTool.AddInsert(PosNode: TCodeTreeNode; procedure TCodeCompletionCodeTool.AddInsert(PosNode: TCodeTreeNode;
const CleanDef, Def, IdentifierName: string); const CleanDef, Def, IdentifierName, Body: string);
var NewInsert, InsertPos, LastInsertPos: TCodeTreeNodeExtension; var NewInsert, InsertPos, LastInsertPos: TCodeTreeNodeExtension;
begin begin
{$IFDEF CTDEBUG} {$IFDEF CTDEBUG}
@ -138,6 +141,7 @@ writeln('[TCodeCompletionCodeTool.AddInsert] ',CleanDef,',',Def,',',Identifierna
Txt:=CleanDef; Txt:=CleanDef;
ExtTxt1:=Def; ExtTxt1:=Def;
ExtTxt2:=IdentifierName; ExtTxt2:=IdentifierName;
ExtTxt3:=Body;
end; end;
if FirstInsert=nil then begin if FirstInsert=nil then begin
FirstInsert:=NewInsert; FirstInsert:=NewInsert;
@ -233,8 +237,9 @@ var Parts: array[TPropPart] of TAtomPosition;
end; end;
var AccessParam, AccessParamPrefix, CleanAccessFunc, AccessFunc, var AccessParam, AccessParamPrefix, CleanAccessFunc, AccessFunc,
CleanParamList, ParamList, PropType: string; CleanParamList, ParamList, PropType, ProcBody, VariableName: string;
InsertPos: integer; InsertPos: integer;
BeautifyCodeOpts: TBeautifyCodeOptions;
begin begin
Result:=false; Result:=false;
for APart:=Low(TPropPart) to High(TPropPart) do for APart:=Low(TPropPart) to High(TPropPart) do
@ -275,14 +280,10 @@ writeln('[TCodeCompletionCodeTool.CompleteProperty] no type : found -> ignore pr
or UpAtomIs('END') or AtomIsChar(';') or (not AtomIsIdentifier(false)) or UpAtomIs('END') or AtomIsChar(';') or (not AtomIsIdentifier(false))
or AtomIsKeyWord then begin or AtomIsKeyWord then begin
// no type name found -> ignore this property // no type name found -> ignore this property
{$IFDEF CTDEBUG} RaiseException('property type expected, but '+GetAtom+' found');
writeln('[TCodeCompletionCodeTool.CompleteProperty] error: no type name found');
{$ENDIF}
Result:=true;
exit;
end; end;
Parts[ppType]:=CurPos; Parts[ppType]:=CurPos;
// read specifiers // parse specifiers
ReadNextAtom; ReadNextAtom;
if UpAtomIs('INDEX') then begin if UpAtomIs('INDEX') then begin
if Parts[ppIndexWord].StartPos>=1 then if Parts[ppIndexWord].StartPos>=1 then
@ -329,14 +330,15 @@ writeln('[TCodeCompletionCodeTool.CompleteProperty] error: no type name found');
RaiseException('Reparsing error (Complete Property)'); RaiseException('Reparsing error (Complete Property)');
PropType:=copy(Src,Parts[ppType].StartPos, PropType:=copy(Src,Parts[ppType].StartPos,
Parts[ppType].EndPos-Parts[ppType].StartPos); Parts[ppType].EndPos-Parts[ppType].StartPos);
BeautifyCodeOpts:=ASourceChangeCache.BeautifyCodeOptions;
// check read specifier // check read specifier
VariableName:='';
if (Parts[ppReadWord].StartPos>0) or (Parts[ppWriteWord].StartPos<1) then if (Parts[ppReadWord].StartPos>0) or (Parts[ppWriteWord].StartPos<1) then
begin begin
{$IFDEF CTDEBUG} {$IFDEF CTDEBUG}
writeln('[TCodeCompletionCodeTool.CompleteProperty] read specifier needed'); writeln('[TCodeCompletionCodeTool.CompleteProperty] read specifier needed');
{$ENDIF} {$ENDIF}
AccessParamPrefix:= AccessParamPrefix:=BeautifyCodeOpts.PropertyReadIdentPrefix;
ASourceChangeCache.BeautifyCodeOptions.PropertyReadIdentPrefix;
if Parts[ppRead].StartPos>0 then if Parts[ppRead].StartPos>0 then
AccessParam:=copy(Src,Parts[ppRead].StartPos, AccessParam:=copy(Src,Parts[ppRead].StartPos,
Parts[ppRead].EndPos-Parts[ppRead].StartPos) Parts[ppRead].EndPos-Parts[ppRead].StartPos)
@ -409,21 +411,24 @@ writeln('[TCodeCompletionCodeTool.CompleteProperty] Error reading param list');
end; end;
end; end;
// add new Insert Node // add new Insert Node
AddInsert(PropNode,CleanAccessFunc,AccessFunc,AccessParam); if CompleteProperties then
AddInsert(PropNode,CleanAccessFunc,AccessFunc,AccessParam,'');
end; end;
end else begin end else begin
// the read identifier is a variable
if Parts[ppRead].StartPos<1 then if Parts[ppRead].StartPos<1 then
AccessParam:=ASourceChangeCache.BeautifyCodeOptions.PrivatVariablePrefix AccessParam:=BeautifyCodeOpts.PrivatVariablePrefix
+copy(Src,Parts[ppName].StartPos, +copy(Src,Parts[ppName].StartPos,
Parts[ppName].EndPos-Parts[ppName].StartPos); Parts[ppName].EndPos-Parts[ppName].StartPos);
// the read identifier is a variable VariableName:=AccessParam;
if not VarExists(UpperCaseStr(AccessParam)) then begin if not VarExists(UpperCaseStr(AccessParam)) then begin
// variable does not exist yet -> add insert demand for variable // variable does not exist yet -> add insert demand for variable
AddInsert(PropNode,UpperCaseStr(AccessParam), if CompleteProperties then
AccessParam+':'+PropType+';',AccessParam); AddInsert(PropNode,UpperCaseStr(AccessParam),
AccessParam+':'+PropType+';',AccessParam,'');
end; end;
end; end;
if Parts[ppRead].StartPos<0 then begin if (Parts[ppRead].StartPos<0) and CompleteProperties then begin
// insert read specifier // insert read specifier
if Parts[ppReadWord].StartPos>0 then begin if Parts[ppReadWord].StartPos>0 then begin
// 'read' keyword exists -> insert read identifier behind // 'read' keyword exists -> insert read identifier behind
@ -439,8 +444,7 @@ writeln('[TCodeCompletionCodeTool.CompleteProperty] Error reading param list');
else else
InsertPos:=Parts[ppType].EndPos; InsertPos:=Parts[ppType].EndPos;
ASourceChangeCache.Replace(gtSpace,gtNone,InsertPos,InsertPos, ASourceChangeCache.Replace(gtSpace,gtNone,InsertPos,InsertPos,
ASourceChangeCache.BeautifyCodeOptions.BeautifyKeyWord('read') BeautifyCodeOpts.BeautifyKeyWord('read')+' '+AccessParam);
+' '+AccessParam);
end; end;
end; end;
end; end;
@ -450,8 +454,7 @@ writeln('[TCodeCompletionCodeTool.CompleteProperty] Error reading param list');
{$IFDEF CTDEBUG} {$IFDEF CTDEBUG}
writeln('[TCodeCompletionCodeTool.CompleteProperty] write specifier needed'); writeln('[TCodeCompletionCodeTool.CompleteProperty] write specifier needed');
{$ENDIF} {$ENDIF}
AccessParamPrefix:= AccessParamPrefix:=BeautifyCodeOpts.PropertyWriteIdentPrefix;
ASourceChangeCache.BeautifyCodeOptions.PropertyWriteIdentPrefix;
if Parts[ppWrite].StartPos>0 then if Parts[ppWrite].StartPos>0 then
AccessParam:=copy(Src,Parts[ppWrite].StartPos, AccessParam:=copy(Src,Parts[ppWrite].StartPos,
Parts[ppWrite].EndPos-Parts[ppWrite].StartPos) Parts[ppWrite].EndPos-Parts[ppWrite].StartPos)
@ -488,6 +491,7 @@ writeln('[TCodeCompletionCodeTool.CompleteProperty] write specifier needed');
if not ProcExists(CleanAccessFunc) then begin if not ProcExists(CleanAccessFunc) then begin
// add insert demand for function // add insert demand for function
// build function code // build function code
ProcBody:='';
if (Parts[ppParamList].StartPos>0) then begin if (Parts[ppParamList].StartPos>0) then begin
MoveCursorToCleanPos(Parts[ppParamList].StartPos); MoveCursorToCleanPos(Parts[ppParamList].StartPos);
ReadNextAtom; ReadNextAtom;
@ -512,8 +516,22 @@ writeln('[TCodeCompletionCodeTool.CompleteProperty] write specifier needed');
end else begin end else begin
if (Parts[ppIndexWord].StartPos<1) then begin if (Parts[ppIndexWord].StartPos<1) then begin
// no param list, no index // no param list, no index
AccessFunc:='procedure '+AccessParam AccessFunc:=
+'(const '+SetPropertyVariablename+': '+PropType+');'; 'procedure '+AccessParam
+'(const '+SetPropertyVariablename+': '+PropType+');';
if VariableName<>'' then begin
// read spec is a variable -> add simple assign code to body
ProcBody:=
'procedure '
+ExtractClassName(PropNode.Parent.Parent,false)+'.'+AccessParam
+'(const '+SetPropertyVariablename+': '+PropType+');'
+BeautifyCodeOpts.LineEnd
+'begin'+BeautifyCodeOpts.LineEnd
+GetIndentStr(BeautifyCodeOpts.Indent)+
+VariableName+':='+SetPropertyVariablename+';'
+BeautifyCodeOpts.LineEnd
+'end;';
end;
end else begin end else begin
// index, no param list // index, no param list
AccessFunc:='procedure '+AccessParam AccessFunc:='procedure '+AccessParam
@ -522,17 +540,19 @@ writeln('[TCodeCompletionCodeTool.CompleteProperty] write specifier needed');
end; end;
end; end;
// add new Insert Node // add new Insert Node
AddInsert(PropNode,CleanAccessFunc,AccessFunc,AccessParam); if CompleteProperties then
AddInsert(PropNode,CleanAccessFunc,AccessFunc,AccessParam,ProcBody);
end; end;
end else begin end else begin
// the write identifier is a variable // the write identifier is a variable
if not VarExists(UpperCaseStr(AccessParam)) then begin if not VarExists(UpperCaseStr(AccessParam)) then begin
// variable does not exist yet -> add insert demand for variable // variable does not exist yet -> add insert demand for variable
AddInsert(PropNode,UpperCaseStr(AccessParam), if CompleteProperties then
AccessParam+':'+PropType+';',AccessParam); AddInsert(PropNode,UpperCaseStr(AccessParam),
AccessParam+':'+PropType+';',AccessParam,'');
end; end;
end; end;
if Parts[ppWrite].StartPos<0 then begin if (Parts[ppWrite].StartPos<0) and CompleteProperties then begin
// insert write specifier // insert write specifier
if Parts[ppWriteWord].StartPos>0 then begin if Parts[ppWriteWord].StartPos>0 then begin
// 'write' keyword exists -> insert write identifier behind // 'write' keyword exists -> insert write identifier behind
@ -553,8 +573,7 @@ writeln('[TCodeCompletionCodeTool.CompleteProperty] write specifier needed');
else else
InsertPos:=Parts[ppType].EndPos; InsertPos:=Parts[ppType].EndPos;
ASourceChangeCache.Replace(gtSpace,gtNone,InsertPos,InsertPos, ASourceChangeCache.Replace(gtSpace,gtNone,InsertPos,InsertPos,
ASourceChangeCache.BeautifyCodeOptions.BeautifyKeyWord('write') BeautifyCodeOpts.BeautifyKeyWord('write')+' '+AccessParam);
+' '+AccessParam);
end; end;
end; end;
end; end;
@ -569,7 +588,7 @@ writeln('[TCodeCompletionCodeTool.CompleteProperty] stored specifier needed');
else else
AccessParam:=copy(Src,Parts[ppName].StartPos, AccessParam:=copy(Src,Parts[ppName].StartPos,
Parts[ppName].EndPos-Parts[ppName].StartPos) Parts[ppName].EndPos-Parts[ppName].StartPos)
+ASourceChangeCache.BeautifyCodeOptions.PropertyStoredIdentPostfix; +BeautifyCodeOpts.PropertyStoredIdentPostfix;
CleanAccessFunc:=UpperCaseStr(AccessParam); CleanAccessFunc:=UpperCaseStr(AccessParam);
// check if procedure exists // check if procedure exists
if (not ProcExists(CleanAccessFunc)) and (not VarExists(CleanAccessFunc)) if (not ProcExists(CleanAccessFunc)) and (not VarExists(CleanAccessFunc))
@ -578,13 +597,15 @@ writeln('[TCodeCompletionCodeTool.CompleteProperty] stored specifier needed');
// build function code // build function code
AccessFunc:='function '+AccessParam+':boolean;'; AccessFunc:='function '+AccessParam+':boolean;';
// add new Insert Node // add new Insert Node
AddInsert(PropNode,CleanAccessFunc,AccessFunc,AccessParam); if CompleteProperties then
AddInsert(PropNode,CleanAccessFunc,AccessFunc,AccessParam,'');
end; end;
if Parts[ppStored].StartPos<0 then begin if Parts[ppStored].StartPos<0 then begin
// insert stored specifier // insert stored specifier
InsertPos:=Parts[ppStoredWord].EndPos; InsertPos:=Parts[ppStoredWord].EndPos;
ASourceChangeCache.Replace(gtSpace,gtNone,InsertPos,InsertPos, if CompleteProperties then
AccessParam); ASourceChangeCache.Replace(gtSpace,gtNone,InsertPos,InsertPos,
AccessParam);
end; end;
end; end;
Result:=true; Result:=true;
@ -766,14 +787,17 @@ var
procedure InsertProcBody(ANodeExt: TCodeTreeNodeExtension); procedure InsertProcBody(ANodeExt: TCodeTreeNodeExtension);
var ProcCode: string; var ProcCode: string;
begin begin
ProcCode:=ANodeExt.ExtTxt1; if ANodeExt.ExtTxt3<>'' then
ProcCode:=ANodeExt.ExtTxt3
else
ProcCode:=ANodeExt.ExtTxt1;
ProcCode:=ASourceChangeCache.BeautifyCodeOptions.AddClassAndNameToProc( ProcCode:=ASourceChangeCache.BeautifyCodeOptions.AddClassAndNameToProc(
ProcCode,TheClassName,''); ProcCode,TheClassName,'');
{$IFDEF CTDEBUG} {$IFDEF CTDEBUG}
writeln('>>> InsertProcBody ',TheClassName,' "',ProcCode,'"'); writeln('>>> InsertProcBody ',TheClassName,' "',ProcCode,'"');
{$ENDIF} {$ENDIF}
ProcCode:=ASourceChangeCache.BeautifyCodeOptions.BeautifyProc( ProcCode:=ASourceChangeCache.BeautifyCodeOptions.BeautifyProc(
ProcCode,Indent,true); ProcCode,Indent,ANodeExt.ExtTxt3='');
ASourceChangeCache.Replace(gtEmptyLine,gtEmptyLine,InsertPos,InsertPos, ASourceChangeCache.Replace(gtEmptyLine,gtEmptyLine,InsertPos,InsertPos,
ProcCode); ProcCode);
if JumpToProcName='' then begin if JumpToProcName='' then begin
@ -883,6 +907,7 @@ writeln('TCodeCompletionCodeTool.CreateMissingProcBodies Gather existing method
+ANodeExt.Txt; // Name+ParamTypeList +ANodeExt.Txt; // Name+ParamTypeList
ExtTxt1:=ASourceChangeCache.BeautifyCodeOptions.AddClassAndNameToProc( ExtTxt1:=ASourceChangeCache.BeautifyCodeOptions.AddClassAndNameToProc(
ANodeExt.ExtTxt1,TheClassName,''); // complete proc head code ANodeExt.ExtTxt1,TheClassName,''); // complete proc head code
ExtTxt3:=ANodeExt.ExtTxt3;
Position:=ANodeExt.Position; Position:=ANodeExt.Position;
end; end;
ClassProcs.Add(NewNodeExt); ClassProcs.Add(NewNodeExt);
@ -966,7 +991,10 @@ writeln('TCodeCompletionCodeTool.CreateMissingProcBodies Gather existing method
MissingNode:=ClassProcs.FindHighest; MissingNode:=ClassProcs.FindHighest;
while (MissingNode<>nil) do begin while (MissingNode<>nil) do begin
ANodeExt:=TCodeTreeNodeExtension(MissingNode.Data); ANodeExt:=TCodeTreeNodeExtension(MissingNode.Data);
ProcCode:=ANodeExt.ExtTxt1; if ANodeExt.ExtTxt3<>'' then
ProcCode:=ANodeExt.ExtTxt3
else
ProcCode:=ANodeExt.ExtTxt1;
if (ProcCode='') then begin if (ProcCode='') then begin
ANode:=TCodeTreeNodeExtension(MissingNode.Data).Node; ANode:=TCodeTreeNodeExtension(MissingNode.Data).Node;
if (ANode<>nil) and (ANode.Desc=ctnProcedure) then begin if (ANode<>nil) and (ANode.Desc=ctnProcedure) then begin
@ -1081,7 +1109,10 @@ writeln('TCodeCompletionCodeTool.CreateMissingProcBodies Gather existing method
end; end;
end; end;
end; end;
ProcCode:=ANodeExt.ExtTxt1; if ANodeExt.ExtTxt3<>'' then
ProcCode:=ANodeExt.ExtTxt3
else
ProcCode:=ANodeExt.ExtTxt1;
if (ProcCode='') then begin if (ProcCode='') then begin
ANode:=ANodeExt.Node; ANode:=ANodeExt.Node;
if (ANode<>nil) and (ANode.Desc=ctnProcedure) then begin if (ANode<>nil) and (ANode.Desc=ctnProcedure) then begin
@ -1095,7 +1126,7 @@ writeln('TCodeCompletionCodeTool.CreateMissingProcBodies Gather existing method
ASourceChangeCache.BeautifyCodeOptions.AddClassAndNameToProc( ASourceChangeCache.BeautifyCodeOptions.AddClassAndNameToProc(
ProcCode,TheClassName,''); ProcCode,TheClassName,'');
ProcCode:=ASourceChangeCache.BeautifyCodeOptions.BeautifyProc( ProcCode:=ASourceChangeCache.BeautifyCodeOptions.BeautifyProc(
ProcCode,Indent,true); ProcCode,Indent,ANodeExt.ExtTxt3='');
ASourceChangeCache.Replace(gtEmptyLine,gtEmptyLine, ASourceChangeCache.Replace(gtEmptyLine,gtEmptyLine,
InsertPos,InsertPos,ProcCode); InsertPos,InsertPos,ProcCode);
if JumpToProcName='' then begin if JumpToProcName='' then begin
@ -1330,6 +1361,7 @@ constructor TCodeCompletionCodeTool.Create;
begin begin
inherited Create; inherited Create;
FSetPropertyVariablename:='AValue'; FSetPropertyVariablename:='AValue';
FCompleteProperties:=true;
end; end;

View File

@ -179,7 +179,7 @@ type
public public
Node: TCodeTreeNode; Node: TCodeTreeNode;
Txt: string; Txt: string;
ExtTxt1, ExtTxt2: string; ExtTxt1, ExtTxt2, ExtTxt3: string;
Position: integer; Position: integer;
Data: Pointer; Data: Pointer;
Next: TCodeTreeNodeExtension; Next: TCodeTreeNodeExtension;
@ -526,6 +526,7 @@ begin
Txt:=''; Txt:='';
ExtTxt1:=''; ExtTxt1:='';
ExtTxt2:=''; ExtTxt2:='';
ExtTxt3:='';
Node:=nil; Node:=nil;
Position:=-1; Position:=-1;
Data:=nil; Data:=nil;