From 9f9b841e7b309690d7c5a4300578e299ef4e8c6c Mon Sep 17 00:00:00 2001 From: Martijn Laan <1092369+martijnlaan@users.noreply.github.com> Date: Thu, 16 Jan 2025 16:40:36 +0100 Subject: [PATCH] Add function definition hints on mouseover for [Code] functions and class members. Always shows all matching class members instead of just those of the object's class. Todo: Missing are 'procedure' and 'function' headers and also those without parameters. --- Projects/Src/IDE.MainForm.pas | 115 +++++++++++++--------- Projects/Src/IDE.ScintStylerInnoSetup.pas | 12 ++- 2 files changed, 81 insertions(+), 46 deletions(-) diff --git a/Projects/Src/IDE.MainForm.pas b/Projects/Src/IDE.MainForm.pas index 50ea3a4c7..1c395c700 100644 --- a/Projects/Src/IDE.MainForm.pas +++ b/Projects/Src/IDE.MainForm.pas @@ -5605,19 +5605,20 @@ procedure TMainForm.MemoCharAdded(Sender: TObject; Ch: AnsiChar); procedure TMainForm.MemoHintShow(Sender: TObject; var Info: TScintHintInfo); - function GetCodeVariableDebugEntryFromFileLineCol(FileIndex, Line, Col: Integer): PVariableDebugEntry; + function GetCodeVariableDebugEntryFromFileLineCol(FileIndex, Line, Col: Integer; out DebugEntry: PVariableDebugEntry): Boolean; var I: Integer; begin { FVariableDebugEntries uses 1-based line and column numbers } Inc(Line); Inc(Col); - Result := nil; + Result := False; for I := 0 to FVariableDebugEntriesCount-1 do begin if (FVariableDebugEntries[I].FileIndex = FileIndex) and (FVariableDebugEntries[I].LineNumber = Line) and (FVariableDebugEntries[I].Col = Col) then begin - Result := @FVariableDebugEntries[I]; + DebugEntry := @FVariableDebugEntries[I]; + Result := True; Break; end; end; @@ -5639,6 +5640,15 @@ procedure TMainForm.MemoHintShow(Sender: TObject; var Info: TScintHintInfo); Result := Length(U); end; + function FindVarOrFuncRange(const Pos: Integer): TScintRange; + begin + { Note: The GetPositionAfter is needed so that when the mouse is over a '.' + between two words, it won't match the word to the left of the '.' } + FActiveMemo.SetDefaultWordChars; + Result.StartPos := FActiveMemo.GetWordStartPosition(FActiveMemo.GetPositionAfter(Pos), True); + Result.EndPos := FActiveMemo.GetWordEndPosition(Pos, True); + end; + function FindConstRange(const Pos: Integer): TScintRange; var BraceLevel, ConstStartPos, Line, LineEndPos, I: Integer; @@ -5679,60 +5689,75 @@ procedure TMainForm.MemoHintShow(Sender: TObject; var Info: TScintHintInfo); end; end; -var - Pos, Line, I, J: Integer; - Output: String; - DebugEntry: PVariableDebugEntry; - ConstRange: TScintRange; + procedure UpdateInfo(var Info: TScintHintInfo; const HintStr: String; const Range: TScintRange; const Memo: TIDEScintEdit); + begin + Info.HintStr := HintStr; + Info.CursorRect.TopLeft := Memo.GetPointFromPosition(Range.StartPos); + Info.CursorRect.BottomRight := Memo.GetPointFromPosition(Range.EndPos); + Info.CursorRect.Bottom := Info.CursorRect.Top + Memo.LineHeight; + Info.HideTimeout := High(Integer); { infinite } + end; + begin - if FDebugClientWnd = 0 then - Exit; - Pos := FActiveMemo.GetPositionFromPoint(Info.CursorPos, True, True); + var Pos := FActiveMemo.GetPositionFromPoint(Info.CursorPos, True, True); if Pos < 0 then Exit; - Line := FActiveMemo.GetLineFromPosition(Pos); - - { Check if cursor is over a [Code] variable } - if (FActiveMemo is TIDEScintFileEdit) and - (FMemosStyler.GetSectionFromLineState(FActiveMemo.Lines.State[Line]) = scCode) then begin - { Note: The '+ 1' is needed so that when the mouse is over a '.' - between two words, it won't match the word to the left of the '.' } - FActiveMemo.SetDefaultWordChars; - I := FActiveMemo.GetWordStartPosition(Pos + 1, True); - J := FActiveMemo.GetWordEndPosition(Pos, True); - if J > I then begin - DebugEntry := GetCodeVariableDebugEntryFromFileLineCol((FActiveMemo as TIDEScintFileEdit).CompilerFileIndex, - Line, GetCodeColumnFromPosition(I)); - if DebugEntry <> nil then begin + var Line := FActiveMemo.GetLineFromPosition(Pos); + + { Check if cursor is over a [Code] variable or function } + if FMemosStyler.GetSectionFromLineState(FActiveMemo.Lines.State[Line]) = scCode then begin + var VarOrFuncRange := FindVarOrFuncRange(Pos); + if VarOrFuncRange.EndPos > VarOrFuncRange.StartPos then begin + var HintStr := ''; + var DebugEntry: PVariableDebugEntry; + if (FActiveMemo is TIDEScintFileEdit) and (FDebugClientWnd <> 0) and + GetCodeVariableDebugEntryFromFileLineCol((FActiveMemo as TIDEScintFileEdit).CompilerFileIndex, + Line, GetCodeColumnFromPosition(VarOrFuncRange.StartPos), DebugEntry) then begin + var Output: String; case EvaluateVariableEntry(DebugEntry, Output) of - 1: Info.HintStr := Output; - 2: Info.HintStr := Output; + 1: HintStr := Output; + 2: HintStr := Output; else - Info.HintStr := 'Unknown error'; + HintStr := 'Unknown error'; + end; + end else begin + var Name := FActiveMemo.GetTextRange(VarOrFuncRange.StartPos, VarOrFuncRange.EndPos); + var ClassMember := False; + var Index := 0; + var Count: Integer; + var Definition := FMemosStyler.GetScriptFunctionDefinition(ClassMember, Name, Index, Count); + if Definition = '' then begin + ClassMember := not ClassMember; + Definition := FMemosStyler.GetScriptFunctionDefinition(ClassMember, Name, Index, Count); end; - Info.CursorRect.TopLeft := FActiveMemo.GetPointFromPosition(I); - Info.CursorRect.BottomRight := FActiveMemo.GetPointFromPosition(J); - Info.CursorRect.Bottom := Info.CursorRect.Top + FActiveMemo.LineHeight; - Info.HideTimeout := High(Integer); { infinite } + while Index < Count-1 do begin + Inc(Index); + Definition := Definition + #13 + FMemosStyler.GetScriptFunctionDefinition(ClassMember, Name, Index); + end; + HintStr := String(Definition); + end; + + if HintStr <> '' then begin + UpdateInfo(Info, HintStr, VarOrFuncRange, FActiveMemo); Exit; end; end; end; - { Check if cursor is over a constant } - ConstRange := FindConstRange(Pos); - if ConstRange.EndPos > ConstRange.StartPos then begin - Info.HintStr := FActiveMemo.GetTextRange(ConstRange.StartPos, ConstRange.EndPos); - case EvaluateConstant(Info.HintStr, Output) of - 1: Info.HintStr := Info.HintStr + ' = "' + Output + '"'; - 2: Info.HintStr := Info.HintStr + ' = Exception: ' + Output; - else - Info.HintStr := Info.HintStr + ' = Unknown error'; + if FDebugClientWnd <> 0 then begin + { Check if cursor is over a constant } + var ConstRange := FindConstRange(Pos); + if ConstRange.EndPos > ConstRange.StartPos then begin + var HintStr := FActiveMemo.GetTextRange(ConstRange.StartPos, ConstRange.EndPos); + var Output: String; + case EvaluateConstant(Info.HintStr, Output) of + 1: HintStr := HintStr + ' = "' + Output + '"'; + 2: HintStr := HintStr + ' = Exception: ' + Output; + else + HintStr := HintStr + ' = Unknown error'; + end; + UpdateInfo(Info, HintStr, ConstRange, FActiveMemo); end; - Info.CursorRect.TopLeft := FActiveMemo.GetPointFromPosition(ConstRange.StartPos); - Info.CursorRect.BottomRight := FActiveMemo.GetPointFromPosition(ConstRange.EndPos); - Info.CursorRect.Bottom := Info.CursorRect.Top + FActiveMemo.LineHeight; - Info.HideTimeout := High(Integer); { infinite } end; end; diff --git a/Projects/Src/IDE.ScintStylerInnoSetup.pas b/Projects/Src/IDE.ScintStylerInnoSetup.pas index 3204f4a7d..96cc316e0 100644 --- a/Projects/Src/IDE.ScintStylerInnoSetup.pas +++ b/Projects/Src/IDE.ScintStylerInnoSetup.pas @@ -141,7 +141,9 @@ TInnoSetupStyler = class(TScintCustomStyler) class function IsParamSection(const Section: TInnoSetupStylerSection): Boolean; class function IsSymbolStyle(const Style: TScintStyleNumber): Boolean; function GetScriptFunctionDefinition(const ClassMember: Boolean; - const Name: String; const Index: Integer; out Count: Integer): AnsiString; + const Name: String; const Index: Integer; out Count: Integer): AnsiString; overload; + function GetScriptFunctionDefinition(const ClassMember: Boolean; + const Name: String; const Index: Integer): AnsiString; overload; function SectionHasFlag(const Section: TInnoSetupStylerSection; const Flag: String): Boolean; property ConstantsWordList: AnsiString read FConstantsWordList; property EventFunctionsWordList[Procedures: Boolean]: AnsiString read GetEventFunctionsWordList; @@ -938,6 +940,14 @@ function TInnoSetupStyler.GetScriptFunctionDefinition(const ClassMember: Boolean end; end; +function TInnoSetupStyler.GetScriptFunctionDefinition( + const ClassMember: Boolean; const Name: String; + const Index: Integer): AnsiString; +begin + var Count: Integer; + Result := GetScriptFunctionDefinition(ClassMember, Name, Index, Count); +end; + function TInnoSetupStyler.GetScriptWordList( ClassOrRecordMembers: Boolean): AnsiString; begin