浏览代码

Add multiple calltip support.

Martijn Laan 1 年之前
父节点
当前提交
2aa9f6313f
共有 5 个文件被更改,包括 78 次插入45 次删除
  1. 8 0
      Components/ScintEdit.pas
  2. 1 1
      ISHelp/isetup.xml
  3. 54 22
      Projects/Src/Compil32/CompForm.pas
  4. 13 20
      Projects/Src/Compil32/ScintStylerInnoSetup.pas
  5. 2 2
      whatsnew.htm

+ 8 - 0
Components/ScintEdit.pas

@@ -24,6 +24,7 @@ type
   TScintChangeHistory = (schDisabled, schMarkers, schIndicators);
   TScintCommand = type NativeInt;
   TScintEditAutoCompleteSelectionEvent = TNotifyEvent;
+  TScintEditCallTipArrowClick = procedure(Sender: TObject; const Up: Boolean) of object;
   TScintEditChangeInfo = record
     Inserting: Boolean;
     StartPos, Length, LinesDelta: Integer;
@@ -115,6 +116,7 @@ type
     FLineNumbers: Boolean;
     FLines: TScintEditStrings;
     FOnAutoCompleteSelection: TScintEditAutoCompleteSelectionEvent;
+    FOnCallTipArrowClick: TScintEditCallTipArrowClick;
     FOnChange: TScintEditChangeEvent;
     FOnCharAdded: TScintEditCharAddedEvent;
     FOnDropFiles: TScintEditDropFilesEvent;
@@ -427,6 +429,7 @@ type
     property WordWrap: Boolean read FWordWrap write SetWordWrap default False;
     property Zoom: Integer read GetZoom write SetZoom default 0;
     property OnAutoCompleteSelection: TScintEditAutoCompleteSelectionEvent read FOnAutoCompleteSelection write FOnAutoCompleteSelection;
+    property OnCallTipArrowClick: TScintEditCallTipArrowClick read FOnCallTipArrowClick write FOnCallTipArrowClick;
     property OnChange: TScintEditChangeEvent read FOnChange write FOnChange;
     property OnCharAdded: TScintEditCharAddedEvent read FOnCharAdded write FOnCharAdded;
     property OnDropFiles: TScintEditDropFilesEvent read FOnDropFiles write FOnDropFiles;
@@ -1424,6 +1427,11 @@ begin
         if Assigned(FOnAutoCompleteSelection) then
           FOnAutoCompleteSelection(Self);
       end;
+    SCN_CALLTIPCLICK:
+      begin
+        if (N.position in [1, 2]) and Assigned(FOnCallTipArrowClick) then
+          FOnCallTipArrowClick(Self, N.position = 1);
+      end;
     SCN_CHARADDED:
       begin
         if Assigned(FOnCharAdded) then

+ 1 - 1
ISHelp/isetup.xml

@@ -3345,7 +3345,7 @@ Filename: "{win}\MYPROG.INI"; Section: "InstallSettings"; Key: "InstallPath"; St
   <td>Fillup autocompletion</td><td>Space for ISPP directives and Flags and Type parameters<br />\ for constants<br />: for constants and section parameters<br />] for sections<br />= for section directives<br />( for [Code]</td>
 </tr>
 <tr>
-  <td>Invoke parameter hint</td><td>Ctrl+Shift+Space</td>
+  <td>Invoke parameter hint or show next definition</td><td>Ctrl+Shift+Space</td>
 </tr>
 <tr>
   <td>Cancel autocomplete or parameter hint</td><td>Esc</td>

+ 54 - 22
Projects/Src/Compil32/CompForm.pas

@@ -73,6 +73,11 @@ type
     StartCallTipWord: Integer;
     FunctionDefinition: AnsiString;
     BraceCount: Integer;
+    LastPosCallTip: Integer;
+    ClassOrRecordMember: Boolean;
+    CurrentCallTipWord: String;
+    CurrentCallTip: Integer;
+    MaxCallTips: Integer;
   end;
 
   TCompileForm = class(TUIStateForm)
@@ -513,11 +518,13 @@ type
     function InitiateAutoCompleteOrCallTipAllowedAtPos(const AMemo: TCompScintEdit;
       const WordStartLinePos, PositionBeforeWordStartPos: Integer): Boolean;
     procedure InitiateAutoComplete(const Key: AnsiChar);
+    procedure UpdateCallTipFunctionDefinition(const Pos: Integer = -1);
     procedure InitiateCallTip(const Key: AnsiChar);
     procedure ContinueCallTip;
     procedure InvalidateStatusPanel(const Index: Integer);
     procedure LoadBreakPointLinesAndUpdateLineMarkers(const AMemo: TCompScintFileEdit);
     procedure LoadKnownIncludedAndHiddenFilesAndUpdateMemos(const AFilename: String);
+    procedure MemoCallTipArrowClick(Sender: TObject; const Up: Boolean);
     procedure MemoChange(Sender: TObject; const Info: TScintEditChangeInfo);
     procedure MemoCharAdded(Sender: TObject; Ch: AnsiChar);
     procedure MainMemoDropFiles(Sender: TObject; X, Y: Integer; AFiles: TStrings);
@@ -711,6 +718,7 @@ begin
   Memo.ShowHint := True;
   Memo.Styler := FMemosStyler;
   Memo.PopupMenu := PopupMenu;
+  Memo.OnCallTipArrowClick := MemoCallTipArrowClick;
   Memo.OnChange := MemoChange;
   Memo.OnCharAdded := MemoCharAdded;
   Memo.OnHintShow := MemoHintShow;
@@ -987,6 +995,8 @@ begin
 
   FKeyMappedMenus := TKeyMappedMenus.Create;
 
+  FCallTipState.MaxCallTips := 1; { Just like SciTE 5.50 }
+
   if CommandLineCompile then begin
     ReadSignTools(FSignTools);
     PostMessage(Handle, WM_StartCommandLineCompile, 0, 0)
@@ -1299,8 +1309,12 @@ begin
     end;
   end else if (Key = VK_SPACE) and (Shift * [ssShift, ssAlt, ssCtrl] = [ssShift, ssCtrl]) then begin
     Key := 0;
-    if not FActiveMemo.CallTipActive then begin
-      FCallTipState.BraceCount := 1;
+    { Based on SciTE 5.50's SciTEBase::MenuCommand IDM_SHOWCALLTIP }
+    if FActiveMemo.CallTipActive then begin
+      FCallTipState.CurrentCallTip := IfThen(FCallTipState.CurrentCallTip + 1 = FCallTipState.MaxCallTips, 0, FCallTipState.CurrentCallTip + 1);
+      UpdateCallTipFunctionDefinition;
+    end else begin
+      FCallTipState.BraceCount := 1; { Missing in SciTE, see https://sourceforge.net/p/scintilla/bugs/2446/ }
       InitiateCallTip(#0);
     end;
   end else begin
@@ -4789,6 +4803,19 @@ begin
     UpdateModifiedPanel;
 end;
 
+procedure TCompileForm.MemoCallTipArrowClick(Sender: TObject;
+  const Up: Boolean);
+begin
+  { Based on SciTE 5.50's SciTEBase::Notify SA::Notification::CallTipClick }
+  if Up and (FCallTipState.CurrentCallTip > 0) then begin
+    Dec(FCallTipState.CurrentCallTip);
+    UpdateCallTipFunctionDefinition;
+  end else if not Up and (FCallTipState.CurrentCallTip + 1 < FCallTipState.MaxCallTips) then begin
+    Inc(FCallTipState.CurrentCallTip);
+    UpdateCallTipFunctionDefinition;
+  end;
+end;
+
 procedure TCompileForm.MemoChange(Sender: TObject; const Info: TScintEditChangeInfo);
 
   procedure MemoLinesInsertedOrDeleted(Memo: TCompScintFileEdit);
@@ -5040,6 +5067,25 @@ begin
   FActiveMemo.ShowAutoComplete(CharsBefore, WordList);
 end;
 
+procedure TCompileForm.UpdateCallTipFunctionDefinition(const Pos: Integer { = -1 });
+begin
+  { Based on SciTE 5.50's SciTEBase::FillFunctionDefinition }
+    
+  if Pos > 0 then
+    FCallTipState.LastPosCallTip := Pos;
+
+  // Should get current api definition
+  var Word := FMemosStyler.GetScriptFunctionDefinition(FCallTipState.ClassOrRecordMember, FCallTipState.CurrentCallTipWord, FCallTipState.CurrentCallTip, FCallTipState.MaxCallTips);
+  if Word <> '' then begin
+    FCallTipState.FunctionDefinition := Word;
+    if FCallTipState.MaxCallTips > 1 then
+      FCallTipState.FunctionDefinition := AnsiString(Format(#1'%d of %d'#2'%s', [FCallTipState.CurrentCallTip+1, FCallTipState.MaxCallTips, FCallTipState.FunctionDefinition]));
+
+    FActiveMemo.ShowCallTip(FCallTipState.LastPosCallTip - Length(FCallTipState.CurrentCallTipWord), FCallTipState.FunctionDefinition);
+    ContinueCallTip;
+  end;
+end;
+
 procedure TCompileForm.InitiateCallTip(const Key: AnsiChar);
 begin
   var Pos := FActiveMemo.CaretPosition;
@@ -5050,12 +5096,10 @@ begin
        FActiveMemo.GetPositionBefore(Pos))) then
     Exit;
 
-  { Based on SciTE 5.50's SciTEBase::StartAutoComplete and
-    SciTEBase::FillFunctionDefinition, without support for multiple calltips }
+  { Based on SciTE 5.50's SciTEBase::StartAutoComplete }
 
-  { StartAutoComplete }
-
-  var CurrentCallTipWord := '';
+  FCallTipState.CurrentCallTip := 0;
+  FCallTipState.CurrentCallTipWord := '';
   var Line := FActiveMemo.CaretLineText;
   var Current := FActiveMemo.CaretPositionInLine;
   var CalltipWordCharacters := FActiveMemo.WordCharsAsSet;
@@ -5089,26 +5133,14 @@ begin
   {$ZEROBASEDSTRINGS ON}
 	while (FCallTipState.StartCalltipWord > 0) and CharInSet(Line[FCallTipState.StartCalltipWord-1], CalltipWordCharacters) do
     Dec(FCallTipState.StartCallTipWord);
-  var ClassOrRecordMember := (FCallTipState.StartCalltipWord > 0) and (Line[FCallTipState.StartCalltipWord-1] = '.');
+  FCallTipState.ClassOrRecordMember := (FCallTipState.StartCalltipWord > 0) and (Line[FCallTipState.StartCalltipWord-1] = '.');
   {$ZEROBASEDSTRINGS OFF}
 
   SetLength(Line, Current);
-  CurrentCallTipWord := Line.Substring(FCallTipState.StartCallTipWord); { Substring is zero-based }
+  FCallTipState.CurrentCallTipWord := Line.Substring(FCallTipState.StartCallTipWord); { Substring is zero-based }
 
   FCallTipState.FunctionDefinition := '';
-
-  { FillFunctionDefinition - if this is separated for multiple calltips support like in SciTE then the following vars
-    need to be moved into FCallTipState: CurrentCallTipWord, ClassOrRecordMember, LastPosCallTip }
-
-  var LastPosCallTip := Pos;
-
-  // Should get current api definition
-  var Word := FMemosStyler.GetScriptFunctionDefinition(ClassOrRecordMember, CurrentCallTipWord);
-  if Word <> '' then begin
-    FCallTipState.FunctionDefinition := Word;
-    FActiveMemo.ShowCallTip(LastPosCallTip - Length(CurrentCallTipWord), FCallTipState.FunctionDefinition);
-    ContinueCallTip;
-  end;
+  UpdateCallTipFunctionDefinition(Pos);
 end;
 
 procedure TCompileForm.ContinueCallTip;

+ 13 - 20
Projects/Src/Compil32/ScintStylerInnoSetup.pas

@@ -102,8 +102,6 @@ type
       const EnumTypeInfo: Pointer);
     procedure BuildScriptFunctionsLists(const ScriptFuncTable: TScriptTable;
       const ClassMembers: Boolean; const SL: TStringList);
-    procedure BuildScriptFunctionsListsFinalize(
-      const ClassMembers: Boolean);
     function BuildWordList(const WordStringList: TStringList): AnsiString;
     procedure BuildSectionsWordList;
     procedure CommitStyleSq(const Style: TInnoSetupStylerStyle;
@@ -140,7 +138,8 @@ type
     class function IsCommentOrPascalStringStyle(const Style: TScintStyleNumber): Boolean;
     class function IsParamSection(const Section: TInnoSetupStylerSection): Boolean;
     class function IsSymbolStyle(const Style: TScintStyleNumber): Boolean;
-    function GetScriptFunctionDefinition(const ClassMember: Boolean; const Name: String): AnsiString;
+    function GetScriptFunctionDefinition(const ClassMember: Boolean;
+      const Name: String; const Index: Integer; out Count: Integer): AnsiString;
     property ConstantsWordList: AnsiString read FConstantsWordList;
     property EventFunctionsWordList[Procedures: Boolean]: AnsiString read GetEventFunctionsWordList;
     property FlagsWordList[Section: TInnoSetupStylerSection]: AnsiString read GetFlagsWordList;
@@ -606,7 +605,6 @@ constructor TInnoSetupStyler.Create(AOwner: TComponent);
         BuildScriptFunctionsLists(ScriptFuncTable, ClassMembers, SL);
       BuildScriptFunctionsLists(DelphiScriptFuncTable, ClassMembers, SL);
       BuildScriptFunctionsLists(ROPSScriptFuncTable, ClassMembers, SL);
-      BuildScriptFunctionsListsFinalize(ClassMembers);
       { Add stuff from this unit }
       for var S in PascalConstants do
         AddWordToList(SL, S, awtScriptConstant);
@@ -637,7 +635,6 @@ constructor TInnoSetupStyler.Create(AOwner: TComponent);
       SL.Clear;
       ClassMembers := True;
       BuildScriptFunctionsLists(PascalMembers_Isxclasses, ClassMembers, SL);
-      BuildScriptFunctionsListsFinalize(ClassMembers);
       for var S in PascalProperties_Isxclasses do
         AddWordToList(SL, S, awtScriptProperty);
       FScriptWordList[True] := BuildWordList(SL);
@@ -789,17 +786,6 @@ begin
   end;
 end;
 
-procedure TInnoSetupStyler.BuildScriptFunctionsListsFinalize(
-  const ClassMembers: Boolean);
-begin
-  for var ScriptFunctions in FScriptFunctionsByName[ClassMembers].Values do begin
-    var N := Length(ScriptFunctions);
-    if N > 1 then
-      for var I := 0 to N-1 do
-        ScriptFunctions[I] := AnsiString(Format(#1'%d of %d'#2'%s', [I+1, N, ScriptFunctions[I]]));
-  end;
-end;
-
 procedure TInnoSetupStyler.BuildISPPDirectivesWordList;
 begin
   var SL := TStringList.Create;
@@ -908,13 +894,20 @@ begin
   Result := FKeywordsWordList[Section];
 end;
 
-function TInnoSetupStyler.GetScriptFunctionDefinition(const ClassMember: Boolean; const Name: String): AnsiString;
+function TInnoSetupStyler.GetScriptFunctionDefinition(const ClassMember: Boolean;
+  const Name: String; const Index: Integer; out Count: Integer): AnsiString;
 begin
   var ScriptFunctions: TFunctionDefinitions;
-  if FScriptFunctionsByName[ClassMember].TryGetValue(Name, ScriptFunctions) then
-    Result := ScriptFunctions[0]
-  else
+  if FScriptFunctionsByName[ClassMember].TryGetValue(Name, ScriptFunctions) then begin
+    Count := Length(ScriptFunctions);
+    var ResultIndex := Index;
+    if ResultIndex >= Count then
+      ResultIndex := Count-1;
+    Result := ScriptFunctions[ResultIndex]
+  end else begin
+    Count := 0;
     Result := '';
+  end;
 end;
 
 function TInnoSetupStyler.GetScriptWordList(

+ 2 - 2
whatsnew.htm

@@ -53,9 +53,9 @@ For conditions of distribution and use, see <a href="files/is/license.txt">LICEN
 <ul>
   <li>Added support for Visual Studio Code-style editor shortcuts, like Ctrl+D to Add Next Occurrence, Ctrl+Shift+K to delete a line and Alt+Click to add an additional cursor.<br />To activate this use the <i>Options</i> menu item in the <i>Tools</i> menu to set the new <i>Keys</i> option in the <i>Editor</i> group to <i>Visual Studio Code</i>.<br />The updated <a href="https://jrsoftware.org/ishelp/index.php?topic=compformshortcuts">Compiler IDE Keyboard And Mouse Commands</a> help topic lists all differences with the classic keyboard and mouse shortcuts.</li>
   <li>Added new shortcuts only available if Visual Studio Code-style editor shortcuts have been activated: Shift+Alt+Down to copy line down and Ctrl+] and Ctrl+[ to ident or unindent lines.</li>
-  <li>Implemented parameter hints for all Pascal Scripting support functions for quick reference to the function's parameter names, types, and order. Parameter hints can be invoked manually by pressing Ctrl+Shift+Space or automatically by using the new <i>Invoke parameter hints automatically</i> option which is enabled by default.</li>
+  <li>Added parameter hints for all Pascal Scripting support functions for quick reference to the function's parameter names, types, and order. Parameter hints can be invoked manually by pressing Ctrl+Shift+Space or automatically by using the new <i>Invoke parameter hints automatically</i> option which is enabled by default.</li>
   <li>Added autocompletion support for all Pascal Scripting support functions, types, constants, etcetera. Existing option <i>Invoke autocompletion automatically</i> controls whether the autocompletion suggestions appear automatically or only when invoked manually by pressing Ctrl+Space or Ctrl+I.</li>
-  <li>Added autocompletion support for all Pascal Scripting support class members and properties. Is not intelligent: always shows members and properties of all classes instead of just those of the object's class.</li>
+  <li>Added parameter hints and autocompletion support for all Pascal Scripting support class members and properties. Both always show all classes' members and properties instead of just those of the object's class.</li>
   <li>Added new <i>Enable section folding</i> option which allows you to temporarily hide sections while editing by clicking the new minus or plus icons in the editor's gutter or by using the new keyboard shortcuts (Ctrl+Shift+[ to fold and Ctrl+Shift+] to unfold) or menu items. Enabled by default.</li>
   <li>The editor's gutter now shows change history to keep track of saved and unsaved modifications. Always enabled.</li>
   <li>The editor's font now defaults to Consolas if available, consistent with most other modern editors.</li>