Skip to content

Allow signature help to explicitly specify "no parameters highlighted" #1271

Open
@jakebailey

Description

@jakebailey

Given code like this:

def foo(a, b): ...

foo(1, 2, |)

If the cursor is on the last parameter to the call, we want to specify that nothing should be highlighted. Additionally, the function may be overloaded, in which case we specify per-signature active parameters (microsoft/vscode#94637). Some of those overloads may not match what the user has written, and so none of the parameters should be highlighted.

The spec says:

	/**
	 * The active parameter of the active signature. If omitted or the value
	 * lies outside the range of `signatures[activeSignature].parameters`
	 * defaults to 0 if the active signature has parameters. If
	 * the active signature has no parameters it is ignored.
	 * In future version of the protocol this property might become
	 * mandatory to better express the active parameter if the
	 * active signature does have any.
	 */
	activeParameter?: uinteger;

And for the the signature itself:

	/**
	 * The index of the active parameter.
	 *
	 * If provided, this is used in place of `SignatureHelp.activeParameter`.
	 *
	 * @since 3.16.0
	 */
	activeParameter?: uinteger;

This means there is no spec-compliant way to say "don't highlight any parameters"; omitting the active parameter on the signature defers to the old-style active parameter field, which will be zero (the first parameter) if not provided or specified with an out of bounds value.

We can work around this in pyright/pylance by making use of the fact that the VS Code LSP client doesn't verify the values its given when they are numbers:

https://github.com/microsoft/vscode-languageserver-node/blob/2645fb54ea1e764aff71dee0ecc8aceff3aabf56/client/src/common/protocolConverter.ts#L587-L598

VS Code doesn't implement the "if out of bounds, assume zero" part of the spec, instead not highlighting a parameter, which is what we want, so it works. We've been using -1 as the out of bounds value: https://github.com/microsoft/pyright/blob/48a5f1284055e61f9887a6e0fbfb6176bae730bf/packages/pyright-internal/src/languageServerBase.ts#L702

However, the specs were retroactively changed to specify uinteger for many values, and some clients strictly check that the value is non-negative (microsoft/pyright#1783), so we will likely need to move to some other out of bounds value to maintain this hack. Looking at other languages, I can see that gopls is also relying on this behavior, providing indexes past the end of the parameter list to avoid highlighting, so we can do that too.

But, swapping one hack for another doesn't really address the original need of being able to explicitly specify that no parameter is selected (for the single signature or for all).

Can the spec be modified in some way to explicitly allow something like this? E.g.:

  • Treat "index past end of parameter list" as "no highlight"; this may match the behavior of existing language servers.
  • Allow explicitly setting null or something to say "no highlight" behind a capability.

Metadata

Metadata

Assignees

No one assigned

    Labels

    feature-requestRequest for new features or functionalityhelp wantedIssues identified as good community contribution opportunitiessignature help

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions