IDE.MainForm.AutoCompleteAndCallTipsHelper.pas 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480
  1. unit IDE.MainForm.AutoCompleteAndCallTipsHelper;
  2. {
  3. Inno Setup
  4. Copyright (C) 1997-2025 Jordan Russell
  5. Portions by Martijn Laan
  6. For conditions of distribution and use, see LICENSE.TXT.
  7. Compiler form - Auto complete & call tips helper which has the tools helper as ancestor
  8. Not used by MainForm: it uses IDE.MainForm.FinalHelper instead
  9. }
  10. interface
  11. uses
  12. Menus,
  13. ScintEdit,
  14. IDE.MainForm, IDE.MainForm.ToolsHelper;
  15. type
  16. TMainFormAutoCompleteAndCallTipsHelper = class helper(TMainFormToolsHelper) for TMainForm
  17. procedure InitiateAutoComplete(const AMemo: TScintEdit; const Key: AnsiChar);
  18. procedure AutoCompleteAndCallTipsHandleCharAdded(const AMemo: TScintEdit; const Ch: AnsiChar);
  19. procedure CallTipsHandleArrowClick(const AMemo: TScintEdit; const Up: Boolean);
  20. procedure CallTipsHandleCtrlSpace(const AMemo: TScintEdit);
  21. { Private }
  22. function _InitiateAutoCompleteOrCallTipAllowedAtPos(const AMemo: TScintEdit;
  23. const WordStartLinePos, PositionBeforeWordStartPos: Integer): Boolean;
  24. procedure _UpdateCallTipFunctionDefinition(const AMemo: TScintEdit; const Pos: Integer = -1);
  25. procedure _InitiateCallTip(const AMemo: TScintEdit; const Key: AnsiChar);
  26. procedure _ContinueCallTip(const AMemo: TScintEdit);
  27. end;
  28. implementation
  29. uses
  30. SysUtils, Math, TypInfo,
  31. Shared.SetupSectionDirectives,
  32. IDE.ScintStylerInnoSetup;
  33. function TMainFormAutoCompleteAndCallTipsHelper._InitiateAutoCompleteOrCallTipAllowedAtPos(const AMemo: TScintEdit;
  34. const WordStartLinePos, PositionBeforeWordStartPos: Integer): Boolean;
  35. begin
  36. Result := (PositionBeforeWordStartPos < WordStartLinePos) or
  37. not FMemosStyler.IsCommentOrPascalStringStyle(AMemo.GetStyleAtPosition(PositionBeforeWordStartPos));
  38. end;
  39. procedure TMainFormAutoCompleteAndCallTipsHelper.InitiateAutoComplete(const AMemo: TScintEdit; const Key: AnsiChar);
  40. function OnlyWhiteSpaceBeforeWord(const AMemo: TScintEdit; const LinePos, WordStartPos: Integer): Boolean;
  41. begin
  42. { Only allow autocompletion if no non-whitespace characters exist before the current word on the line }
  43. var I := WordStartPos;
  44. Result := False;
  45. while I > LinePos do begin
  46. I := AMemo.GetPositionBefore(I);
  47. if I < LinePos then
  48. Exit; { shouldn't get here }
  49. const C = AMemo.GetByteAtPosition(I);
  50. if C > ' ' then
  51. Exit;
  52. end;
  53. Result := True;
  54. end;
  55. begin
  56. if AMemo.AutoCompleteActive or AMemo.ReadOnly then
  57. Exit;
  58. if Key = #0 then begin
  59. { If a character is typed then Scintilla will handle selections but
  60. otherwise we should empty them and also make sure the caret is visible
  61. before we start autocompletion }
  62. AMemo.SetEmptySelections;
  63. AMemo.ScrollCaretIntoView;
  64. end;
  65. const CaretPos = AMemo.CaretPosition;
  66. const Line = AMemo.GetLineFromPosition(CaretPos);
  67. const LinePos = AMemo.GetPositionFromLine(Line);
  68. const WordStartPos = AMemo.GetWordStartPosition(CaretPos, True);
  69. const WordEndPos = AMemo.GetWordEndPosition(CaretPos, True);
  70. const CharsBefore = CaretPos - WordStartPos;
  71. { Don't auto start autocompletion after a character is typed if there are any
  72. word characters adjacent to the character }
  73. if Key <> #0 then begin
  74. if CharsBefore > 1 then
  75. Exit;
  76. if WordEndPos > CaretPos then
  77. Exit;
  78. end;
  79. var WordList: AnsiString;
  80. case AMemo.GetByteAtPosition(WordStartPos) of
  81. '#':
  82. begin
  83. if not OnlyWhiteSpaceBeforeWord(AMemo, LinePos, WordStartPos) then
  84. Exit;
  85. WordList := FMemosStyler.ISPPDirectivesWordList;
  86. AMemo.SetAutoCompleteFillupChars(' ');
  87. end;
  88. '{':
  89. begin
  90. WordList := FMemosStyler.ConstantsWordList;
  91. AMemo.SetAutoCompleteFillupChars('\:');
  92. end;
  93. '[':
  94. begin
  95. if not OnlyWhiteSpaceBeforeWord(AMemo, LinePos, WordStartPos) then
  96. Exit;
  97. WordList := FMemosStyler.SectionsWordList;
  98. AMemo.SetAutoCompleteFillupChars('');
  99. end;
  100. else
  101. begin
  102. const Section = FMemosStyler.GetSectionFromLineState(AMemo.Lines.State[Line]);
  103. if Section = scCode then begin
  104. { Space can only initiate autocompletion after non whitespace }
  105. if (Key = ' ') and OnlyWhiteSpaceBeforeWord(AMemo, LinePos, WordStartPos) then
  106. Exit;
  107. const PositionBeforeWordStartPos = AMemo.GetPositionBefore(WordStartPos);
  108. if Key <> #0 then begin
  109. AMemo.StyleNeeded(PositionBeforeWordStartPos); { Make sure the typed character has been styled }
  110. if not _InitiateAutoCompleteOrCallTipAllowedAtPos(AMemo, LinePos, PositionBeforeWordStartPos) then
  111. Exit;
  112. end;
  113. WordList := '';
  114. { Autocomplete event functions if the current word on the line has
  115. exactly 1 space before it which has the word 'function' or
  116. 'procedure' before it which has only whitespace before it }
  117. if (PositionBeforeWordStartPos >= LinePos) and (AMemo.GetByteAtPosition(PositionBeforeWordStartPos) <= ' ') then begin
  118. const FunctionWordEndPos = PositionBeforeWordStartPos;
  119. const FunctionWordStartPos = AMemo.GetWordStartPosition(FunctionWordEndPos, True);
  120. if OnlyWhiteSpaceBeforeWord(AMemo, LinePos, FunctionWordStartPos) then begin
  121. const FunctionWord = AMemo.GetTextRange(FunctionWordStartPos, FunctionWordEndPos);
  122. if SameText(FunctionWord, 'procedure') then
  123. WordList := FMemosStyler.EventFunctionsWordList[True]
  124. else if SameText(FunctionWord, 'function') then
  125. WordList := FMemosStyler.EventFunctionsWordList[False];
  126. if WordList <> '' then
  127. AMemo.SetAutoCompleteFillupChars('');
  128. end;
  129. end;
  130. { If no event function was found then autocomplete script functions,
  131. types, etc if the current word has no dot before it }
  132. if WordList = '' then begin
  133. const ClassOrRecordMember = (PositionBeforeWordStartPos >= LinePos) and (AMemo.GetByteAtPosition(PositionBeforeWordStartPos) = '.');
  134. WordList := FMemosStyler.ScriptWordList[ClassOrRecordMember];
  135. AMemo.SetAutoCompleteFillupChars('');
  136. end;
  137. if WordList = '' then
  138. Exit;
  139. end else begin
  140. const IsParamSection = FMemosStyler.IsParamSection(Section);
  141. var FoundSemicolon := False;
  142. var FoundFlagsOrType := False;
  143. var FoundSetupDirectiveName := '';
  144. var FoundMultipleSetupDirectiveValues := False;
  145. var I := WordStartPos;
  146. while I > LinePos do begin
  147. I := AMemo.GetPositionBefore(I);
  148. if I < LinePos then
  149. Exit; { shouldn't get here }
  150. const C = AMemo.GetByteAtPosition(I);
  151. { Note: The first time we get here C equals the character before the current word,
  152. like a space before the current flag }
  153. if IsParamSection and (C in [';', ':']) and
  154. FMemosStyler.IsSymbolStyle(AMemo.GetStyleAtPosition(I)) then begin { Make sure it's an stSymbol ';' or ':' and not one inside a quoted string or comment }
  155. FoundSemicolon := C = ';';
  156. if not FoundSemicolon then begin
  157. const ParameterWordEndPos = I;
  158. const ParameterWordStartPos = AMemo.GetWordStartPosition(ParameterWordEndPos, True);
  159. const ParameterWord = AMemo.GetTextRange(ParameterWordStartPos, ParameterWordEndPos);
  160. FoundFlagsOrType := SameText(ParameterWord, 'Flags') or
  161. ((Section in [scInstallDelete, scUninstallDelete]) and SameText(ParameterWord, 'Type'));
  162. end else
  163. FoundFlagsOrType := False;
  164. if FoundSemicolon or FoundFlagsOrType then
  165. Break;
  166. end;
  167. if ((Section = scLangOptions) and (C = '.')) or ((Section = scSetup) and (C = '=')) then begin
  168. { Verify that a word (language or directive name) precedes the '.' or '=', then check for
  169. any non-whitespace characters before the word. Among other things, this ensures
  170. we're not inside a comment. }
  171. const NameStartPos = AMemo.GetWordStartPosition(I, True);
  172. if (NameStartPos >= I) or not OnlyWhiteSpaceBeforeWord(AMemo, LinePos, NameStartPos) then
  173. Exit;
  174. if Section = scSetup then begin
  175. const NameEndPos = AMemo.GetWordEndPosition(NameStartPos, True);
  176. FoundSetupDirectiveName := AMemo.GetTextRange(NameStartPos, NameEndPos);
  177. end;
  178. Break;
  179. end else if C > ' ' then begin
  180. if IsParamSection and not (Section in [scInstallDelete, scUninstallDelete]) and
  181. (FMemosStyler.FlagsWordList[Section] <> '') then begin
  182. { Verify word before the current word (or before that when we get here again) is
  183. a valid flag and if so, continue looking before it instead of stopping }
  184. const FlagEndPos = AMemo.GetWordEndPosition(I, True);
  185. const FlagStartPos = AMemo.GetWordStartPosition(I, True);
  186. const FlagWord = AMemo.GetTextRange(FlagStartPos, FlagEndPos);
  187. if FMemosStyler.SectionHasFlag(Section, FlagWord) or FlagWord.StartsWith('{#') then
  188. I := FlagStartPos
  189. else
  190. Exit;
  191. end else if Section = scSetup then begin
  192. { Continue looking for '='. We don't do a verification like it does for
  193. flags above because we don't know the directive name yet. In fact, we
  194. don't even know whether we are before or after the '='. As a workaround
  195. we check for the expected style before '=', which is stKeyword or stComment,
  196. and only continue if we don't find that. }
  197. if not FMemosStyler.IsCommentOrKeywordStyle(AMemo.GetStyleAtPosition(I)) then begin
  198. FoundMultipleSetupDirectiveValues := True;
  199. I := AMemo.GetWordStartPosition(I, True);
  200. end else
  201. Exit;
  202. end else
  203. Exit; { Non-whitespace which should not be there }
  204. end;
  205. end;
  206. { Space can only initiate autocompletion after ';' or 'Flags:' or 'Type:' or a [Setup] directive }
  207. if (Key = ' ') and not (FoundSemicolon or FoundFlagsOrType or (FoundSetupDirectiveName <> '')) then
  208. Exit;
  209. if FoundSetupDirectiveName <> '' then begin
  210. WordList := '';
  211. const V = GetEnumValue(TypeInfo(TSetupSectionDirective), SetupSectionDirectivePrefix + FoundSetupDirectiveName);
  212. if V <> -1 then begin
  213. const Directive = TSetupSectionDirective(V);
  214. if not FoundMultipleSetupDirectiveValues or
  215. FMemosStyler.SetupSectionDirectiveValueIsMultiValue[Directive] then
  216. WordList := FMemosStyler.SetupSectionDirectiveValueWordList[Directive];
  217. end;
  218. if WordList = '' then
  219. Exit;
  220. AMemo.SetAutoCompleteFillupChars(' ');
  221. end else if FoundFlagsOrType then begin
  222. WordList := FMemosStyler.FlagsWordList[Section];
  223. if WordList = '' then { Should never be True, since we already checked above }
  224. Exit;
  225. AMemo.SetAutoCompleteFillupChars(' ');
  226. end else begin
  227. WordList := FMemosStyler.KeywordsWordList[Section];
  228. if WordList = '' then { CustomMessages }
  229. Exit;
  230. if IsParamSection then
  231. AMemo.SetAutoCompleteFillupChars(':')
  232. else
  233. AMemo.SetAutoCompleteFillupChars('=');
  234. end;
  235. end;
  236. end;
  237. end;
  238. AMemo.ShowAutoComplete(CharsBefore, WordList);
  239. end;
  240. procedure TMainFormAutoCompleteAndCallTipsHelper._UpdateCallTipFunctionDefinition(const AMemo: TScintEdit;
  241. const Pos: Integer { = -1 });
  242. begin
  243. { Based on SciTE 5.50's SciTEBase::FillFunctionDefinition }
  244. if Pos > 0 then
  245. FCallTipState.LastPosCallTip := Pos;
  246. // Should get current api definition
  247. var FunctionDefinition := FMemosStyler.GetScriptFunctionDefinition(FCallTipState.ClassOrRecordMember, FCallTipState.CurrentCallTipWord, FCallTipState.CurrentCallTip, FCallTipState.MaxCallTips);
  248. if ((FCallTipState.MaxCallTips = 1) and FunctionDefinition.HasParams) or //if there's a single definition then only show if it has a parameter
  249. (FCallTipState.MaxCallTips > 1) then begin //if there's multiple then show always just like MemoHintShow, so even the one without parameters if it exists
  250. FCallTipState.FunctionDefinition := FunctionDefinition.ScriptFuncWithoutHeader;
  251. if FCallTipState.MaxCallTips > 1 then
  252. FCallTipState.FunctionDefinition := AnsiString(Format(#1'%d of %d'#2'%s', [FCallTipState.CurrentCallTip+1, FCallTipState.MaxCallTips, FCallTipState.FunctionDefinition]));
  253. AMemo.ShowCallTip(FCallTipState.LastPosCallTip - Length(FCallTipState.CurrentCallTipWord), FCallTipState.FunctionDefinition);
  254. _ContinueCallTip(AMemo);
  255. end;
  256. end;
  257. procedure TMainFormAutoCompleteAndCallTipsHelper._InitiateCallTip(const AMemo: TScintEdit; const Key: AnsiChar);
  258. begin
  259. var Pos := AMemo.CaretPosition;
  260. if (FMemosStyler.GetSectionFromLineState(AMemo.Lines.State[AMemo.GetLineFromPosition(Pos)]) <> scCode) or
  261. ((Key <> #0) and not _InitiateAutoCompleteOrCallTipAllowedAtPos(AMemo,
  262. AMemo.GetPositionFromLine(AMemo.GetLineFromPosition(Pos)),
  263. AMemo.GetPositionBefore(Pos))) then
  264. Exit;
  265. { Based on SciTE 5.50's SciTEBase::StartAutoComplete }
  266. FCallTipState.CurrentCallTip := 0;
  267. FCallTipState.CurrentCallTipWord := '';
  268. var Line := AMemo.CaretLineText;
  269. var Current := AMemo.CaretPositionInLine;
  270. const CallTipWordCharacters = AMemo.WordCharsAsSet;
  271. {$ZEROBASEDSTRINGS ON}
  272. repeat
  273. var Braces := 0;
  274. while ((Current > 0) and ((Braces <> 0) or not (Line[Current-1] = '('))) do begin
  275. if Line[Current-1] = '(' then
  276. Dec(Braces)
  277. else if Line[Current-1] = ')' then
  278. Inc(Braces);
  279. Dec(Current);
  280. Dec(Pos);
  281. end;
  282. if Current > 0 then begin
  283. Dec(Current);
  284. Dec(Pos);
  285. end else
  286. Break;
  287. while (Current > 0) and (Line[Current-1] <= ' ') do begin
  288. Dec(Current);
  289. Dec(Pos);
  290. end
  291. until not ((Current > 0) and not CharInSet(Line[Current-1], CallTipWordCharacters));
  292. {$ZEROBASEDSTRINGS OFF}
  293. if Current <= 0 then
  294. Exit;
  295. FCallTipState.StartCallTipWord := Current - 1;
  296. {$ZEROBASEDSTRINGS ON}
  297. while (FCallTipState.StartCallTipWord > 0) and CharInSet(Line[FCallTipState.StartCallTipWord-1], CallTipWordCharacters) do
  298. Dec(FCallTipState.StartCallTipWord);
  299. FCallTipState.ClassOrRecordMember := (FCallTipState.StartCallTipWord > 0) and (Line[FCallTipState.StartCallTipWord-1] = '.');
  300. {$ZEROBASEDSTRINGS OFF}
  301. SetLength(Line, Current);
  302. FCallTipState.CurrentCallTipWord := Line.Substring(FCallTipState.StartCallTipWord); { Substring is zero-based }
  303. FCallTipState.FunctionDefinition := '';
  304. _UpdateCallTipFunctionDefinition(AMemo, Pos);
  305. end;
  306. procedure TMainFormAutoCompleteAndCallTipsHelper._ContinueCallTip(const AMemo: TScintEdit);
  307. begin
  308. { Based on SciTE 5.50's SciTEBase::ContinueCallTip }
  309. const Line = AMemo.CaretLineText;
  310. const Current = AMemo.CaretPositionInLine;
  311. var Braces := 0;
  312. var Commas := 0;
  313. for var I := FCallTipState.StartCallTipWord to Current-1 do begin
  314. {$ZEROBASEDSTRINGS ON}
  315. if CharInSet(Line[I], ['(', '[']) then
  316. Inc(Braces)
  317. else if CharInSet(Line[I], [')', ']']) and (Braces > 0) then
  318. Dec(Braces)
  319. else if (Braces = 1) and (Line[I] = ',') then
  320. Inc(Commas);
  321. {$ZEROBASEDSTRINGS OFF}
  322. end;
  323. {$ZEROBASEDSTRINGS ON}
  324. var StartHighlight := 0;
  325. const FunctionDefinition = FCallTipState.FunctionDefinition;
  326. const FunctionDefinitionLength = Length(FunctionDefinition);
  327. while (StartHighlight < FunctionDefinitionLength) and not (FunctionDefinition[StartHighlight] = '(') do
  328. Inc(StartHighlight);
  329. if (StartHighlight < FunctionDefinitionLength) and (FunctionDefinition[StartHighlight] = '(') then
  330. Inc(StartHighlight);
  331. while (StartHighlight < FunctionDefinitionLength) and (Commas > 0) do begin
  332. if FunctionDefinition[StartHighlight] in [',', ';'] then
  333. Dec(Commas);
  334. // If it reached the end of the argument list it means that the user typed in more
  335. // arguments than the ones listed in the calltip
  336. if FunctionDefinition[StartHighlight] = ')' then
  337. Commas := 0
  338. else
  339. Inc(StartHighlight);
  340. end;
  341. if (StartHighlight < FunctionDefinitionLength) and (FunctionDefinition[StartHighlight] in [',', ';']) then
  342. Inc(StartHighlight);
  343. var EndHighlight := StartHighlight;
  344. while (EndHighlight < FunctionDefinitionLength) and not (FunctionDefinition[EndHighlight] in [',', ';']) and not (FunctionDefinition[EndHighlight] = ')') do
  345. Inc(EndHighlight);
  346. {$ZEROBASEDSTRINGS OFF}
  347. AMemo.SetCallTipHighlight(StartHighlight, EndHighlight);
  348. end;
  349. procedure TMainFormAutoCompleteAndCallTipsHelper.AutoCompleteAndCallTipsHandleCharAdded(
  350. const AMemo: TScintEdit; const Ch: AnsiChar);
  351. begin
  352. { Based on SciTE 5.50's SciTEBase::CharAdded but with an altered interaction
  353. between calltips and autocomplete }
  354. var DoAutoComplete := False;
  355. if AMemo.CallTipActive then begin
  356. if Ch = ')' then begin
  357. Dec(FCallTipState.BraceCount);
  358. if FCallTipState.BraceCount < 1 then
  359. AMemo.CancelCallTip
  360. else if FOptions.AutoCallTips then
  361. _InitiateCallTip(AMemo, Ch);
  362. end else if Ch = '(' then begin
  363. Inc(FCallTipState.BraceCount);
  364. if FOptions.AutoCallTips then
  365. _InitiateCallTip(AMemo, Ch);
  366. end else
  367. _ContinueCallTip(AMemo);
  368. end else if AMemo.AutoCompleteActive then begin
  369. if Ch = '(' then begin
  370. Inc(FCallTipState.BraceCount);
  371. if FOptions.AutoCallTips then begin
  372. _InitiateCallTip(AMemo, Ch);
  373. if not AMemo.CallTipActive then begin
  374. { Normally the calltip activation means any active autocompletion gets
  375. cancelled by Scintilla but if the current word has no call tip then
  376. we should make sure ourselves that the added brace still cancels
  377. the currently active autocompletion }
  378. DoAutoComplete := True;
  379. end;
  380. end;
  381. end else if Ch = ')' then
  382. Dec(FCallTipState.BraceCount)
  383. else
  384. DoAutoComplete := True;
  385. end else if Ch = '(' then begin
  386. FCallTipState.BraceCount := 1;
  387. if FOptions.AutoCallTips then
  388. _InitiateCallTip(AMemo, Ch);
  389. end else
  390. DoAutoComplete := True;
  391. if DoAutoComplete then begin
  392. case Ch of
  393. 'A'..'Z', 'a'..'z', '_', '#', '{', '[', '<', '0'..'9':
  394. if not AMemo.AutoCompleteActive and FOptions.AutoAutoComplete and not (Ch in ['0'..'9']) then
  395. InitiateAutoComplete(AMemo, Ch);
  396. else
  397. const RestartAutoComplete = (Ch in [' ', '.', '=']) and
  398. (FOptions.AutoAutoComplete or AMemo.AutoCompleteActive);
  399. AMemo.CancelAutoComplete;
  400. if RestartAutoComplete then
  401. InitiateAutoComplete(AMemo, Ch);
  402. end;
  403. end;
  404. end;
  405. procedure TMainFormAutoCompleteAndCallTipsHelper.CallTipsHandleArrowClick(const AMemo: TScintEdit;
  406. const Up: Boolean);
  407. begin
  408. { Based on SciTE 5.50's SciTEBase::Notify SA::Notification::CallTipClick }
  409. if Up and (FCallTipState.CurrentCallTip > 0) then begin
  410. Dec(FCallTipState.CurrentCallTip);
  411. _UpdateCallTipFunctionDefinition(AMemo);
  412. end else if not Up and (FCallTipState.CurrentCallTip + 1 < FCallTipState.MaxCallTips) then begin
  413. Inc(FCallTipState.CurrentCallTip);
  414. _UpdateCallTipFunctionDefinition(AMemo);
  415. end;
  416. end;
  417. procedure TMainFormAutoCompleteAndCallTipsHelper.CallTipsHandleCtrlSpace(const AMemo: TScintEdit);
  418. begin
  419. { Based on SciTE 5.50's SciTEBase::MenuCommand IDM_SHOWCALLTIP }
  420. if AMemo.CallTipActive then begin
  421. FCallTipState.CurrentCallTip := IfThen(FCallTipState.CurrentCallTip + 1 = FCallTipState.MaxCallTips, 0, FCallTipState.CurrentCallTip + 1);
  422. _UpdateCallTipFunctionDefinition(AMemo);
  423. end else begin
  424. FCallTipState.BraceCount := 1; { Missing in SciTE, see https://sourceforge.net/p/scintilla/bugs/2446/ }
  425. _InitiateCallTip(AMemo, #0);
  426. end;
  427. end;
  428. end.