Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle empty object capabilities as truthy where applicable #1707

Merged
merged 1 commit into from
Sep 14, 2023

Conversation

bstaletic
Copy link
Collaborator

@bstaletic bstaletic commented Sep 11, 2023

Another one of those "be vscode plox" things.
Servers seem to expect things like

{
	"capabilities": {
		"whateverProvider": {}
	}
}

to mean that the server is really a provider of whatever. Earliest offender is the swift server being a code action provider.

Please take extra care wen reviewing this thing.

Unresolved things:

  1. Are we correctly handling textDocumentSync?
  2. Type hierarchy needs to get the same treatment once Implement simple type hierarchy support #1704 is accepted.

This change is Reviewable

@bstaletic bstaletic force-pushed the empty_truthy_thingy branch 2 times, most recently from dc5338a to 12c6c42 Compare September 12, 2023 05:50
Copy link
Member

@puremourning puremourning left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed 1 of 1 files at r1, all commit messages.
Reviewable status: 0 of 2 LGTMs obtained (waiting on @bstaletic)


ycmd/completers/language_server/language_server_completer.py line 3546 at r1 (raw file):

def _IsCapabilityProvided( capabilities, query ):
  capability = capabilities.get( query )
  return bool( capability or capability == {} )

this looks a little odd, the RHS of or is already a bool, so I think bool( capability ) or capability == {} maybe.

But perhaps what we're really saying is that we should return True if:

  • the query is in the dict
  • the value of query in the dict is not False or None (json null)

Interestingly, not all providers are allowed to be False, for example:

	 * The server provides code lens.
	 */
	codeLensProvider?: CodeLensOptions;

This may be:

  • not supplied (return False)
  • null/None (return False)
  • a CodeLensOptions object (return True)

Wheres:

	codeActionProvider?: boolean | CodeActionOptions;

This may be:

  • not supplied (return False)
  • null/None (return False)
  • True (return True)
  • False (return False)
  • a CodeActionOptions object (return True)

sadly, we may need a third argument to this function allow_boolean which says if True/False is valid for the entry in the spec.

something like

def _IsCapabilityProvided( c, q, allow_boolean=True ):
   if not q in c: return False
   v = c[q]
   if type( v ) == bool:
     if not allow_boolean: return False
     return v
   if type( v ) == dict:
     return True
   return False

maybe maybe?

Copy link
Collaborator Author

@bstaletic bstaletic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: 0 of 2 LGTMs obtained (waiting on @puremourning)


ycmd/completers/language_server/language_server_completer.py line 3546 at r1 (raw file):

bool( capability ) or capability == {}

That is what I intended to write!

I definitely was not considering getting a bool where it is not expected. Or rather I was and thought it would be fine to accept True even against the protocol.
Yes, that's questionable.

That last suggestion of yours seems expensive. For semantic tokens and signature help we query capabilities on every request. Maybe we need to start being careful about those?

The following should cover all cases "by the book" without unnecessary type comparisons and dict lookups:

def _IsCapabilityProvided( c, q, allow_boolean=True ):
    v = c.get( q )
    if v is None: return False
    t = type( v )
    if t == bool:
        return v if allow_boolean else False
    return t == dict

Copy link
Member

@puremourning puremourning left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: 0 of 2 LGTMs obtained (waiting on @bstaletic)


ycmd/completers/language_server/language_server_completer.py line 3546 at r1 (raw file):

Previously, bstaletic (Boris Staletic) wrote…

bool( capability ) or capability == {}

That is what I intended to write!

I definitely was not considering getting a bool where it is not expected. Or rather I was and thought it would be fine to accept True even against the protocol.
Yes, that's questionable.

That last suggestion of yours seems expensive. For semantic tokens and signature help we query capabilities on every request. Maybe we need to start being careful about those?

The following should cover all cases "by the book" without unnecessary type comparisons and dict lookups:

def _IsCapabilityProvided( c, q, allow_boolean=True ):
    v = c.get( q )
    if v is None: return False
    t = type( v )
    if t == bool:
        return v if allow_boolean else False
    return t == dict

I think you're right. Just fix the bool() expression in your first version and keep it simple. The pedantic-but-correct version is harder to follow, harder to explain and just a bit ugly :D

Copy link
Collaborator Author

@bstaletic bstaletic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: 0 of 2 LGTMs obtained (waiting on @puremourning)


ycmd/completers/language_server/language_server_completer.py line 3546 at r1 (raw file):

Previously, puremourning (Ben Jackson) wrote…

I think you're right. Just fix the bool() expression in your first version and keep it simple. The pedantic-but-correct version is harder to follow, harder to explain and just a bit ugly :D

Done.

Copy link
Member

@puremourning puremourning left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:lgtm:

Reviewed 1 of 1 files at r2, all commit messages.
Reviewable status: 1 of 2 LGTMs obtained (waiting on @bstaletic)

Another one of those "be vscode plox" things.
Servers seem to expect things like
{
	"capabilities": {
		"whateverProvider": {}
	}
}
to mean that the server is really a provider of whatever.
Earliest offender is the swift server being a code action provider.
@bstaletic
Copy link
Collaborator Author

CI is green. I am happy with this PR. Codecov got rate limited again.
@puremourning I'm only not merging this in case you wish to inspect the latest changes.

Copy link
Member

@puremourning puremourning left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:lgtm:

Reviewed 1 of 1 files at r3, all commit messages.
Reviewable status: 1 of 2 LGTMs obtained (waiting on @bstaletic)

@bstaletic bstaletic added the Ship It! Manual override to merge a PR by maintainer label Sep 14, 2023
@mergify
Copy link
Contributor

mergify bot commented Sep 14, 2023

Thanks for sending a PR!

@mergify mergify bot merged commit cff0e09 into ycm-core:master Sep 14, 2023
14 checks passed
@bstaletic bstaletic deleted the empty_truthy_thingy branch September 14, 2023 18:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Ship It! Manual override to merge a PR by maintainer
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants