ManualOnlyCompletionProvider.cs 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. using System.Threading;
  2. using System.Threading.Tasks;
  3. using RoslynPad.Editor;
  4. public sealed class ManualOnlyCompletionProvider : ICodeEditorCompletionProvider
  5. {
  6. private readonly ICodeEditorCompletionProvider _inner;
  7. // 0 = blocked, 1 = allow exactly one completion request
  8. private int _allowOnce;
  9. public ManualOnlyCompletionProvider(ICodeEditorCompletionProvider inner)
  10. => _inner = inner;
  11. /// <summary>
  12. /// Call this immediately before letting the editor execute its completion action (Ctrl + Space).
  13. /// </summary>
  14. public void AllowNextCompletionOnce()
  15. => Interlocked.Exchange(ref _allowOnce, 1);
  16. /// <summary>
  17. /// If false, blocks signature help popups (parameter hints).
  18. /// </summary>
  19. public bool AllowSignatureHelp { get; set; } = false;
  20. /// <summary>
  21. /// If true, a request with triggerChar == null is treated as a manual invoke
  22. /// even if you didn't call AllowNextCompletionOnce().
  23. /// </summary>
  24. public bool TreatNullTriggerAsManualInvoke { get; set; } = true;
  25. /// <summary>
  26. /// If true, allows '.' to trigger completion while typing (classic IDE feel),
  27. /// while still blocking letter-by-letter popups.
  28. /// </summary>
  29. public bool AllowDotTrigger { get; set; } = false;
  30. public Task<CompletionResult> GetCompletionData(int position, char? triggerChar, bool useSignatureHelp)
  31. {
  32. // No results object for this build:
  33. static CompletionResult EmptyResult() => new CompletionResult(null, null, useHardSelection: false);
  34. // 1) Signature help requested?
  35. if (useSignatureHelp && !AllowSignatureHelp)
  36. return Task.FromResult(EmptyResult());
  37. // 2) Typed character triggers (auto popup on keystrokes)
  38. if (triggerChar is not null)
  39. {
  40. if (!(AllowDotTrigger && triggerChar == '.'))
  41. return Task.FromResult(EmptyResult());
  42. }
  43. // 3) Manual gating: either explicitly armed once, or inferred from null trigger
  44. if (Interlocked.Exchange(ref _allowOnce, 0) == 1)
  45. return _inner.GetCompletionData(position, triggerChar, useSignatureHelp);
  46. if (TreatNullTriggerAsManualInvoke && triggerChar is null && !useSignatureHelp)
  47. return _inner.GetCompletionData(position, triggerChar, useSignatureHelp);
  48. return Task.FromResult(EmptyResult());
  49. }
  50. }