diff --git a/Python/Product/PythonTools/PythonTools.csproj b/Python/Product/PythonTools/PythonTools.csproj
index 438a509243..29515d8543 100644
--- a/Python/Product/PythonTools/PythonTools.csproj
+++ b/Python/Product/PythonTools/PythonTools.csproj
@@ -433,6 +433,7 @@
+
diff --git a/Python/Product/PythonTools/PythonTools/Editor/LanguagePreferences.cs b/Python/Product/PythonTools/PythonTools/Editor/LanguagePreferences.cs
index 16b3384309..4bde5dbf5d 100644
--- a/Python/Product/PythonTools/PythonTools/Editor/LanguagePreferences.cs
+++ b/Python/Product/PythonTools/PythonTools/Editor/LanguagePreferences.cs
@@ -25,6 +25,7 @@ internal class LanguagePreferences : IVsTextManagerEvents2, IDisposable {
private readonly IVsTextManager _textMgr;
private readonly uint _cookie;
private LANGPREFERENCES _preferences;
+ private volatile bool _autoListParams;
private bool _isDisposed;
public LanguagePreferences(IServiceProvider site, Guid languageGuid) {
@@ -41,6 +42,7 @@ public LanguagePreferences(IServiceProvider site, Guid languageGuid) {
langPrefs[0].fLineNumbers = 1;
ErrorHandler.ThrowOnFailure(_textMgr.SetUserPreferences(null, null, langPrefs, null));
_preferences = langPrefs[0];
+ _autoListParams = _preferences.fAutoListParams != 0;
var guid = typeof(IVsTextManagerEvents2).GUID;
IConnectionPoint connectionPoint = null;
@@ -103,6 +105,7 @@ public int OnUserPreferencesChanged2(VIEWPREFERENCES2[] viewPrefs, FRAMEPREFEREN
_preferences.IndentStyle = langPrefs[0].IndentStyle;
_preferences.fAutoListMembers = langPrefs[0].fAutoListMembers;
_preferences.fAutoListParams = langPrefs[0].fAutoListParams;
+ _autoListParams = langPrefs[0].fAutoListParams != 0;
_preferences.fHideAdvancedAutoListMembers = langPrefs[0].fHideAdvancedAutoListMembers;
_preferences.fDropdownBar = langPrefs[0].fDropdownBar;
_preferences.fLineNumbers = langPrefs[0].fLineNumbers;
@@ -122,7 +125,7 @@ public int OnUserPreferencesChanged2(VIEWPREFERENCES2[] viewPrefs, FRAMEPREFEREN
public bool AutoListMembers => _preferences.fAutoListMembers != 0;
- public bool AutoListParams => _preferences.fAutoListParams != 0;
+ public bool AutoListParams => _autoListParams;
#endregion
}
diff --git a/Python/Product/PythonTools/PythonTools/LanguageServerClient/PythonLanguageClient.cs b/Python/Product/PythonTools/PythonTools/LanguageServerClient/PythonLanguageClient.cs
index 0c6f41747d..c5939c9e6e 100644
--- a/Python/Product/PythonTools/PythonTools/LanguageServerClient/PythonLanguageClient.cs
+++ b/Python/Product/PythonTools/PythonTools/LanguageServerClient/PythonLanguageClient.cs
@@ -98,6 +98,7 @@ internal sealed class PythonLanguageClient : ILanguageClient, ILanguageClientCus
private List _workspaceFolders = new List();
private FileWatcher.Listener _fileListener;
private static TaskCompletionSource _readyTcs = new TaskCompletionSource();
+ private readonly PythonSignatureHelpMiddleLayer _signatureHelpMiddleLayer;
private bool _loaded = false;
// Set by the dispose action before any other cleanup; consulted by
// TriggerWorkspaceUpdateConfig and GetSettings so teardown cannot
@@ -106,6 +107,7 @@ internal sealed class PythonLanguageClient : ILanguageClient, ILanguageClientCus
public PythonLanguageClient() {
_disposables = new Common.Core.Disposables.DisposableBag(GetType().Name);
+ _signatureHelpMiddleLayer = new PythonSignatureHelpMiddleLayer();
}
public string ContentTypeName => PythonCoreConstants.ContentType;
@@ -118,7 +120,7 @@ public PythonLanguageClient() {
public object InitializationOptions { get; private set; }
public IEnumerable FilesToWatch => null;
- public object MiddleLayer => null;
+ public object MiddleLayer => _signatureHelpMiddleLayer;
public object CustomMessageTarget { get; private set; }
public bool IsInitialized { get; private set; }
public bool Loaded => this._loaded;
@@ -187,7 +189,8 @@ public async Task OnLoadedAsync() {
await JoinableTaskContext.Factory.SwitchToMainThreadAsync();
// Force the package to load, since this is a MEF component,
// there is no guarantee it has been loaded.
- Site.GetPythonToolsService();
+ var pyService = Site.GetPythonToolsService();
+ _signatureHelpMiddleLayer.Initialize(await pyService.GetLangPrefsAsync());
// Indicate to python tools service we've loaded.
_loaded = true;
diff --git a/Python/Product/PythonTools/PythonTools/LanguageServerClient/PythonSignatureHelpMiddleLayer.cs b/Python/Product/PythonTools/PythonTools/LanguageServerClient/PythonSignatureHelpMiddleLayer.cs
new file mode 100644
index 0000000000..d2c060fd7f
--- /dev/null
+++ b/Python/Product/PythonTools/PythonTools/LanguageServerClient/PythonSignatureHelpMiddleLayer.cs
@@ -0,0 +1,70 @@
+using System;
+using System.Globalization;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.PythonTools.Editor;
+using Microsoft.VisualStudio.LanguageServer.Client;
+using Microsoft.VisualStudio.LanguageServer.Protocol;
+using Newtonsoft.Json.Linq;
+
+namespace Microsoft.PythonTools.LanguageServerClient {
+#if !DEV18_OR_LATER
+#pragma warning disable CS0618
+#endif
+ internal sealed class PythonSignatureHelpMiddleLayer :
+#if DEV18_OR_LATER
+ ILanguageClientMiddleLayer2 {
+#else
+ ILanguageClientMiddleLayer {
+#endif
+ private LanguagePreferences _languagePreferences;
+
+ internal void Initialize(LanguagePreferences languagePreferences) {
+ Volatile.Write(ref _languagePreferences, languagePreferences ?? throw new ArgumentNullException(nameof(languagePreferences)));
+ }
+
+ public bool CanHandle(string methodName) =>
+ string.Equals(methodName, Methods.TextDocumentSignatureHelpName, StringComparison.Ordinal);
+
+ public Task HandleRequestAsync(string methodName, JToken methodParam, Func> sendRequest) {
+ if (ShouldSuppressAutomaticSignatureHelp(methodParam)) {
+ return Task.FromResult(JValue.CreateNull());
+ }
+
+ return sendRequest(methodParam);
+ }
+
+ public Task HandleNotificationAsync(string methodName, JToken methodParam, Func sendNotification) =>
+ sendNotification(methodParam);
+
+ private bool ShouldSuppressAutomaticSignatureHelp(JToken methodParam) {
+ var languagePreferences = Volatile.Read(ref _languagePreferences);
+ if (languagePreferences == null || languagePreferences.AutoListParams) {
+ return false;
+ }
+
+ if (!(methodParam is JObject request) ||
+ !(request["context"] is JObject context) ||
+ context["triggerKind"]?.Type != JTokenType.Integer ||
+ context["isRetrigger"]?.Type != JTokenType.Boolean ||
+ context["isRetrigger"].Value() ||
+ (context["activeSignatureHelp"] != null && context["activeSignatureHelp"].Type != JTokenType.Null)) {
+ return false;
+ }
+
+ if (!int.TryParse(
+ context["triggerKind"].ToString(),
+ NumberStyles.Integer,
+ CultureInfo.InvariantCulture,
+ out var triggerKind)) {
+ return false;
+ }
+
+ return triggerKind == (int)SignatureHelpTriggerKind.TriggerCharacter ||
+ triggerKind == (int)SignatureHelpTriggerKind.ContentChange;
+ }
+ }
+#if !DEV18_OR_LATER
+#pragma warning restore CS0618
+#endif
+}
diff --git a/Python/Product/PythonTools/PythonTools/Options/PythonAdvancedEditorOptionsControl.Designer.cs b/Python/Product/PythonTools/PythonTools/Options/PythonAdvancedEditorOptionsControl.Designer.cs
index cfe8c19fe2..933aba3510 100644
--- a/Python/Product/PythonTools/PythonTools/Options/PythonAdvancedEditorOptionsControl.Designer.cs
+++ b/Python/Product/PythonTools/PythonTools/Options/PythonAdvancedEditorOptionsControl.Designer.cs
@@ -27,6 +27,7 @@ private void InitializeComponent() {
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(PythonAdvancedEditorOptionsControl));
this._completeFunctionParens = new System.Windows.Forms.CheckBox();
this._autoImportCompletions = new System.Windows.Forms.CheckBox();
+ this._parameterInformation = new System.Windows.Forms.CheckBox();
tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
tableLayoutPanel1.SuspendLayout();
this.SuspendLayout();
@@ -36,6 +37,7 @@ private void InitializeComponent() {
resources.ApplyResources(tableLayoutPanel1, "tableLayoutPanel1");
tableLayoutPanel1.Controls.Add(this._autoImportCompletions, 0, 0);
tableLayoutPanel1.Controls.Add(this._completeFunctionParens, 0, 1);
+ tableLayoutPanel1.Controls.Add(this._parameterInformation, 0, 2);
tableLayoutPanel1.Name = "tableLayoutPanel1";
//
// _completeFunctionParens
@@ -52,6 +54,13 @@ private void InitializeComponent() {
tableLayoutPanel1.SetColumnSpan(this._autoImportCompletions, 2);
this._autoImportCompletions.Name = "_autoImportCompletions";
this._autoImportCompletions.UseVisualStyleBackColor = true;
+ //
+ // _parameterInformation
+ //
+ resources.ApplyResources(this._parameterInformation, "_parameterInformation");
+ tableLayoutPanel1.SetColumnSpan(this._parameterInformation, 2);
+ this._parameterInformation.Name = "_parameterInformation";
+ this._parameterInformation.UseVisualStyleBackColor = true;
//
// PythonAdvancedEditorOptionsControl
//
@@ -69,5 +78,6 @@ private void InitializeComponent() {
#endregion
private System.Windows.Forms.CheckBox _autoImportCompletions;
private System.Windows.Forms.CheckBox _completeFunctionParens;
+ private System.Windows.Forms.CheckBox _parameterInformation;
}
}
diff --git a/Python/Product/PythonTools/PythonTools/Options/PythonAdvancedEditorOptionsControl.cs b/Python/Product/PythonTools/PythonTools/Options/PythonAdvancedEditorOptionsControl.cs
index e48ad93344..853cad4b37 100644
--- a/Python/Product/PythonTools/PythonTools/Options/PythonAdvancedEditorOptionsControl.cs
+++ b/Python/Product/PythonTools/PythonTools/Options/PythonAdvancedEditorOptionsControl.cs
@@ -22,9 +22,12 @@ public PythonAdvancedEditorOptionsControl() {
InitializeComponent();
}
- internal void SyncControlWithPageSettings(PythonToolsService pyService) {
+ internal bool ParameterInformation => _parameterInformation.Checked;
+
+ internal void SyncControlWithPageSettings(PythonToolsService pyService, bool parameterInformation) {
_autoImportCompletions.Checked = pyService.AdvancedEditorOptions.AutoImportCompletions;
_completeFunctionParens.Checked = pyService.AdvancedEditorOptions.CompleteFunctionParens;
+ _parameterInformation.Checked = parameterInformation;
}
internal void SyncPageWithControlSettings(PythonToolsService pyService) {
diff --git a/Python/Product/PythonTools/PythonTools/Options/PythonAdvancedEditorOptionsControl.resx b/Python/Product/PythonTools/PythonTools/Options/PythonAdvancedEditorOptionsControl.resx
index a7dea5b27b..9d7b74b703 100644
--- a/Python/Product/PythonTools/PythonTools/Options/PythonAdvancedEditorOptionsControl.resx
+++ b/Python/Product/PythonTools/PythonTools/Options/PythonAdvancedEditorOptionsControl.resx
@@ -201,6 +201,39 @@
1
+
+ Left
+
+
+ True
+
+
+ 11, 88
+
+
+ 11, 6, 11, 6
+
+
+ 237, 29
+
+
+ 3
+
+
+ &Parameter information
+
+
+ _parameterInformation
+
+
+ System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ tableLayoutPanel1
+
+
+ 2
+
Fill
@@ -211,7 +244,7 @@
6, 6, 6, 6
- 3
+ 4
699, 510
@@ -232,7 +265,7 @@
0
- <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="_completeFunctionParens" Row="1" RowSpan="1" Column="0" ColumnSpan="2" /><Control Name="_autoImportCompletions" Row="0" RowSpan="1" Column="0" ColumnSpan="2" /></Controls><Columns Styles="Percent,100,Absolute,545" /><Rows Styles="AutoSize,0,AutoSize,0,Absolute,20" /></TableLayoutSettings>
+ <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="_completeFunctionParens" Row="1" RowSpan="1" Column="0" ColumnSpan="2" /><Control Name="_autoImportCompletions" Row="0" RowSpan="1" Column="0" ColumnSpan="2" /><Control Name="_parameterInformation" Row="2" RowSpan="1" Column="0" ColumnSpan="2" /></Controls><Columns Styles="Percent,100,Absolute,545" /><Rows Styles="AutoSize,0,AutoSize,0,AutoSize,0,Absolute,20" /></TableLayoutSettings>
True
diff --git a/Python/Product/PythonTools/PythonTools/Options/PythonAdvancedEditorOptionsPage.cs b/Python/Product/PythonTools/PythonTools/Options/PythonAdvancedEditorOptionsPage.cs
index 7b67acd6ed..3c6c4e8227 100644
--- a/Python/Product/PythonTools/PythonTools/Options/PythonAdvancedEditorOptionsPage.cs
+++ b/Python/Product/PythonTools/PythonTools/Options/PythonAdvancedEditorOptionsPage.cs
@@ -21,6 +21,7 @@ namespace Microsoft.PythonTools.Options {
[ComVisible(true)]
public class PythonAdvancedEditorOptionsPage : PythonDialogPage {
private PythonAdvancedEditorOptionsControl _window;
+ private bool _parameterInformation = true;
// replace the default UI of the dialog page w/ our own UI.
protected override IWin32Window Window {
@@ -38,18 +39,33 @@ protected override IWin32Window Window {
/// a call to to commit the new
/// values.
///
- public override void ResetSettings() => PyService.AdvancedEditorOptions.Reset();
+ public override void ResetSettings() {
+ PyService.AdvancedEditorOptions.Reset();
+ _parameterInformation = true;
+ _window?.SyncControlWithPageSettings(PyService, _parameterInformation);
+ }
public override void LoadSettingsFromStorage() {
PyService.AdvancedEditorOptions.Load();
+ _parameterInformation = PyService.GetLanguagePreferences().fAutoListParams != 0;
// Synchronize UI with backing properties.
- _window?.SyncControlWithPageSettings(PyService);
+ _window?.SyncControlWithPageSettings(PyService, _parameterInformation);
}
public override void SaveSettingsToStorage() {
// Synchronize backing properties with UI.
_window?.SyncPageWithControlSettings(PyService);
+ if (_window != null) {
+ _parameterInformation = _window.ParameterInformation;
+ }
PyService.AdvancedEditorOptions.Save();
+
+ var languagePreferences = PyService.GetLanguagePreferences();
+ var autoListParams = _parameterInformation ? 1u : 0u;
+ if (languagePreferences.fAutoListParams != autoListParams) {
+ languagePreferences.fAutoListParams = autoListParams;
+ PyService.SetLanguagePreferences(languagePreferences);
+ }
}
}
}