diff --git a/components/codetools/identcompletiontool.pas b/components/codetools/identcompletiontool.pas index 49a5911e18..f1b9756d88 100644 --- a/components/codetools/identcompletiontool.pas +++ b/components/codetools/identcompletiontool.pas @@ -79,6 +79,7 @@ type FParamList: string; FParamListValid: boolean; function GetParamList: string; + procedure SetParamList(const AValue: string); public Compatibility: TIdentifierCompatibility; HasChilds: boolean; // identifier can contain childs (class, record) @@ -87,8 +88,10 @@ type Level: integer; Node: TCodeTreeNode; Tool: TFindDeclarationTool; + DefaultDesc: TCodeTreeNodeDesc; function AsString: string; - property ParamList: string read GetParamList; + function GetDesc: TCodeTreeNodeDesc; + property ParamList: string read GetParamList write SetParamList; end; TIdentifierListFlag = (ilfFilteredListNeedsUpdate); @@ -101,6 +104,7 @@ type FHistory: TIdentifierHistoryList; FItems: TAVLTree; // tree of TIdentifierListItem (completely sorted) FIdentView: TAVLTree; // tree of TIdentHistListItem sorted for identifiers + FIdentSearchItem: TIdentifierListItem; FPrefix: string; procedure SetHistory(const AValue: TIdentifierHistoryList); procedure UpdateFilteredList; @@ -113,6 +117,7 @@ type procedure Add(NewItem: TIdentifierListItem); function Count: integer; function GetFilteredCount: integer; + function HasIdentifier(Identifier: PChar; const ParamList: string): boolean; public property Prefix: string read FPrefix write SetPrefix; property FilteredItems[Index: integer]: TIdentifierListItem @@ -159,7 +164,10 @@ type CurrentIdentifierList: TIdentifierList; function CollectAllIdentifiers(Params: TFindDeclarationParams; const FoundContext: TFindContext): TIdentifierFoundResult; - procedure GatherPredefinedIdentifiers; + procedure GatherPredefinedIdentifiers(CleanPos: integer; + const Context: TFindContext); + procedure GatherUsefulIdentifiers(CleanPos: integer; + const Context: TFindContext); public function GatherIdentifiers(const CursorPos: TCodeXYPosition; var IdentifierList: TIdentifierList): boolean; @@ -320,6 +328,7 @@ begin FFlags:=[ilfFilteredListNeedsUpdate]; FItems:=TAVLTree.Create(@CompareIdentListItems); FIdentView:=TAVLTree.Create(@CompareIdentListItemsForIdents); + FIdentSearchItem:=TIdentifierListItem.Create; end; destructor TIdentifierList.Destroy; @@ -328,6 +337,7 @@ begin FItems.Free; FIdentView.Free; FFilteredList.Free; + FIdentSearchItem.Free; inherited Destroy; end; @@ -366,6 +376,15 @@ begin Result:=FFilteredList.Count; end; +function TIdentifierList.HasIdentifier(Identifier: PChar; + const ParamList: string): boolean; +begin + FIdentSearchItem.Identifier:=Identifier; + FIdentSearchItem.ParamList:=''; + Result:=FIdentView.FindKey(FIdentSearchItem, + @CompareIdentListItemsForIdents)<>nil; +end; + { TIdentCompletionTool } function TIdentCompletionTool.CollectAllIdentifiers( @@ -437,9 +456,64 @@ begin CurrentIdentifierList.Add(NewItem); end; -procedure TIdentCompletionTool.GatherPredefinedIdentifiers; +procedure TIdentCompletionTool.GatherPredefinedIdentifiers(CleanPos: integer; + const Context: TFindContext); +// Add predefined identifiers + + function StatementLevel: integer; + var + ANode: TCodeTreeNode; + begin + Result:=0; + ANode:=Context.Node; + while (ANode<>nil) and (not (ANode.Desc in [ctnBeginBlock,ctnAsmBlock])) do + begin + ANode:=ANode.Parent; + inc(Result); + end; + if ANode=nil then Result:=0; + end; + +var + NewItem: TIdentifierListItem; + ProcNode: TCodeTreeNode; begin - // ToDo: + if Context.Node.Desc in AllPascalStatements then begin + if Context.Tool.NodeIsInAMethod(Context.Node) + and (not CurrentIdentifierList.HasIdentifier('Self','')) then begin + // method body -> add 'Self' + NewItem:=TIdentifierListItem.Create; + NewItem.Compatibility:=icompUnknown; + NewItem.HasChilds:=true; + NewItem.Identifier:='Self'; + NewItem.Level:=StatementLevel; + NewItem.Node:=nil; + NewItem.Tool:=nil; + NewItem.DefaultDesc:=ctnVarDefinition; + CurrentIdentifierList.Add(NewItem); + end; + ProcNode:=Context.Node.GetNodeOfType(ctnProcedure); + if Context.Tool.NodeIsFunction(ProcNode) + and (not CurrentIdentifierList.HasIdentifier('Result','')) then begin + // function body -> add 'Result' + NewItem:=TIdentifierListItem.Create; + NewItem.Compatibility:=icompUnknown; + NewItem.HasChilds:=false; + NewItem.Identifier:='Result'; + NewItem.Level:=StatementLevel; + NewItem.Node:=nil; + NewItem.Tool:=nil; + NewItem.DefaultDesc:=ctnNone; + CurrentIdentifierList.Add(NewItem); + end; + end; +end; + +procedure TIdentCompletionTool.GatherUsefulIdentifiers(CleanPos: integer; + const Context: TFindContext); +begin + GatherPredefinedIdentifiers(CleanPos,Context); + end; function TIdentCompletionTool.GatherIdentifiers( @@ -519,11 +593,11 @@ begin {$ENDIF} GatherContext.Tool.FindIdentifierInContext(Params); end; - // add predefined identifiers + // add useful identifiers without context {$IFDEF CTDEBUG} writeln('TIdentCompletionTool.GatherIdentifiers G'); {$ENDIF} - GatherPredefinedIdentifiers; + GatherUsefulIdentifiers(CleanCursorPos,GatherContext); Result:=true; finally @@ -541,15 +615,23 @@ end; function TIdentifierListItem.GetParamList: string; begin if not FParamListValid then begin - if Node.Desc=ctnProcedure then + if (Node<>nil) and (Node.Desc=ctnProcedure) then FParamList:=Tool.ExtractProcHead(Node, [phpWithoutClassKeyword,phpWithoutClassName, - phpWithoutName,phpInUpperCase]); + phpWithoutName,phpInUpperCase]) + else + FParamList:=''; FParamListValid:=true; end; Result:=FParamList; end; +procedure TIdentifierListItem.SetParamList(const AValue: string); +begin + FParamList:=AValue; + FParamListValid:=true; +end; + function TIdentifierListItem.AsString: string; begin Result:=IdentifierCompatibilityNames[Compatibility]; @@ -560,9 +642,19 @@ begin Result:=Result+' History='+IntToStr(HistoryIndex); Result:=Result+' Ident='+GetIdentifier(Identifier); Result:=Result+' Lvl='+IntToStr(Level); - Result:=Result+' File='+Tool.MainFilename; - Result:=Result+' Node='+Node.DescAsString - +' "'+StringToPascalConst(copy(Tool.Src,Node.StartPos,50))+'"'; + if Tool<>nil then + Result:=Result+' File='+Tool.MainFilename; + if Node<>nil then + Result:=Result+' Node='+Node.DescAsString + +' "'+StringToPascalConst(copy(Tool.Src,Node.StartPos,50))+'"'; +end; + +function TIdentifierListItem.GetDesc: TCodeTreeNodeDesc; +begin + if Node<>nil then + Result:=Node.Desc + else + Result:=DefaultDesc; end; { TIdentifierHistoryList } @@ -628,7 +720,7 @@ begin // create a new history item NewHistItem:=TIdentHistListItem.Create; NewHistItem.Identifier:=GetIdentifier(NewItem.Identifier); - NewHistItem.NodeDesc:=NewItem.Node.Desc; + NewHistItem.NodeDesc:=NewItem.GetDesc; NewHistItem.ParamList:=NewItem.ParamList; AdjustIndex:=0; end; diff --git a/ide/sourceeditprocs.pas b/ide/sourceeditprocs.pas index 4985fa664f..8c015c2f66 100644 --- a/ide/sourceeditprocs.pas +++ b/ide/sourceeditprocs.pas @@ -81,69 +81,70 @@ var AColor: TColor; ANode: TCodeTreeNode; begin - with ACanvas do begin - if CurrentCompletionType=ctIdentCompletion then begin - // draw - IdentItem:=CodeToolBoss.IdentifierList.FilteredItems[Index]; - if IdentItem=nil then begin - TextOut(x+1, y, 'PaintCompletionItem: BUG in codetools'); - exit; + if CurrentCompletionType=ctIdentCompletion then begin + // draw + IdentItem:=CodeToolBoss.IdentifierList.FilteredItems[Index]; + if IdentItem=nil then begin + ACanvas.TextOut(x+1, y, 'PaintCompletionItem: BUG in codetools'); + exit; + end; + // first write the type + // var, procedure, property, function, type, const + case IdentItem.GetDesc of + + ctnVarDefinition: + begin + AColor:=clMaroon; + s:='var'; end; - // first write the type - // var, procedure, property, function, type, const - case IdentItem.Node.Desc of - ctnVarDefinition: - begin - AColor:=clMaroon; - s:='var'; - end; + ctnTypeDefinition: + begin + AColor:=clDkGray; + s:='type'; + end; - ctnTypeDefinition: - begin - AColor:=clDkGray; - s:='type'; - end; + ctnConstDefinition: + begin + AColor:=clOlive; + s:='const'; + end; - ctnConstDefinition: - begin - AColor:=clOlive; - s:='const'; - end; - - ctnProcedure: - if IdentItem.Tool.NodeIsFunction(IdentItem.Node) then begin - AColor:=clTeal; - s:='function'; - end else begin - AColor:=clNavy; - s:='procedure'; - end; - - ctnProperty: - begin - AColor:=clPurple; - s:='property'; - end; - - else - AColor:=clGray; - s:=''; + ctnProcedure: + if (IdentItem.Node<>nil) + and IdentItem.Tool.NodeIsFunction(IdentItem.Node) then begin + AColor:=clTeal; + s:='function'; + end else begin + AColor:=clNavy; + s:='procedure'; end; - SetFontColor(AColor); - TextOut(x+1,y,s); - inc(x,TextWidth('procedure ')); + ctnProperty: + begin + AColor:=clPurple; + s:='property'; + end; - SetFontColor(clBlack); - Font.Style:=Font.Style+[fsBold]; - s:=GetIdentifier(IdentItem.Identifier); - TextOut(x+1,y,s); - inc(x,TextWidth(s)); - Font.Style:=Font.Style-[fsBold]; + else + AColor:=clGray; + s:=''; + end; + + SetFontColor(AColor); + ACanvas.TextOut(x+1,y,s); + inc(x,ACanvas.TextWidth('procedure ')); + SetFontColor(clBlack); + ACanvas.Font.Style:=ACanvas.Font.Style+[fsBold]; + s:=GetIdentifier(IdentItem.Identifier); + ACanvas.TextOut(x+1,y,s); + inc(x,ACanvas.TextWidth(s)); + ACanvas.Font.Style:=ACanvas.Font.Style-[fsBold]; + + if IdentItem.Node<>nil then begin case IdentItem.Node.Desc of - + ctnProcedure: begin s:=IdentItem.Tool.ExtractProcHead(IdentItem.Node, @@ -151,14 +152,14 @@ begin phpWithParameterNames,phpWithDefaultValues,phpWithResultType, phpWithOfObject]); end; - + ctnProperty: begin s:=IdentItem.Tool.ExtractProperty(IdentItem.Node, [phpWithoutName,phpWithVarModifiers, phpWithParameterNames,phpWithDefaultValues,phpWithResultType]); end; - + ctnVarDefinition: begin ANode:=IdentItem.Tool.FindTypeNodeOfDefinition(IdentItem.Node); @@ -179,42 +180,46 @@ begin else exit; - - end; - - SetFontColor(clBlack); - TextOut(x+1,y,s); + end; end else begin - // parse AKey for text and style - i := 1; - while i <= Length(AKey) do begin - case AKey[i] of - #1, #2: - begin - // set color - Font.Color := (Ord(AKey[i + 3]) shl 8 + Ord(AKey[i + 2])) shl 8 - + Ord(AKey[i + 1]); - inc(i, 4); - end; - #3: - begin - // set style - case AKey[i + 1] of - 'B': Font.Style := Font.Style + [fsBold]; - 'b': Font.Style := Font.Style - [fsBold]; - 'U': Font.Style := Font.Style + [fsUnderline]; - 'u': Font.Style := Font.Style - [fsUnderline]; - 'I': Font.Style := Font.Style + [fsItalic]; - 'i': Font.Style := Font.Style - [fsItalic]; - end; - inc(i, 2); - end; - else - TextOut(x+1, y, AKey[i]); - x := x + TextWidth(AKey[i]); - inc(i); + // IdentItem.Node=nil + exit; + end; + + SetFontColor(clBlack); + ACanvas.TextOut(x+1,y,s); + + end else begin + // parse AKey for text and style + i := 1; + while i <= Length(AKey) do begin + case AKey[i] of + #1, #2: + begin + // set color + ACanvas.Font.Color := (Ord(AKey[i + 3]) shl 8 + + Ord(AKey[i + 2])) shl 8 + + Ord(AKey[i + 1]); + inc(i, 4); end; + #3: + begin + // set style + case AKey[i + 1] of + 'B': ACanvas.Font.Style := ACanvas.Font.Style + [fsBold]; + 'b': ACanvas.Font.Style := ACanvas.Font.Style - [fsBold]; + 'U': ACanvas.Font.Style := ACanvas.Font.Style + [fsUnderline]; + 'u': ACanvas.Font.Style := ACanvas.Font.Style - [fsUnderline]; + 'I': ACanvas.Font.Style := ACanvas.Font.Style + [fsItalic]; + 'i': ACanvas.Font.Style := ACanvas.Font.Style - [fsItalic]; + end; + inc(i, 2); + end; + else + ACanvas.TextOut(x+1, y, AKey[i]); + x := x + ACanvas.TextWidth(AKey[i]); + inc(i); end; end; end; @@ -231,14 +236,16 @@ begin ValueType:=icvIdentifier; if IdentItem<>nil then begin Result:=GetIdentifier(IdentItem.Identifier); - case IdentItem.Node.Desc of + case IdentItem.GetDesc of ctnProcedure: - if IdentItem.Tool.ProcNodeHasParamList(IdentItem.Node) then + if (IdentItem.Node<>nil) + and IdentItem.Tool.ProcNodeHasParamList(IdentItem.Node) then ValueType:=icvProcWithParams; ctnProperty: - if IdentItem.Tool.PropertyNodeHasParamList(IdentItem.Node) then + if (IdentItem.Node<>nil) + and IdentItem.Tool.PropertyNodeHasParamList(IdentItem.Node) then ValueType:=icvIndexedProp; end;