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

Remove HoverContentsEmpty from HoverContents #162

Closed
Hogeyama opened this issue May 7, 2019 · 8 comments · Fixed by #166
Closed

Remove HoverContentsEmpty from HoverContents #162

Hogeyama opened this issue May 7, 2019 · 8 comments · Fixed by #166

Comments

@Hogeyama
Copy link

Hogeyama commented May 7, 2019

HoverContentsEmpty, a constructor added in this commit, does not exist in original Language Server Protocol.

interface Hover {
    contents: MarkedString | MarkedString[] | MarkupContent;
    range?: Range;
}

This results in hie sending an invalid message to the client.
Isn't it better to remove this constructor?
Semigroup would be enough if we want to combine results from multiple sources.

@alanz
Copy link
Collaborator

alanz commented May 7, 2019

HoverContentsEmpty was added because the spec says the reply can be

result: Hover | null defined as follows:

and we did not support the null case.

This was as requested in #141

@Hogeyama
Copy link
Author

Hogeyama commented May 7, 2019

I'm sorry for missing the issue.
The spec says Hover is nullable, but Hover.contents is not, doesn't it?
I think what we need to fix the issue is to modify the FromJSON instance like this:

instance FromJSON HoverContents where
  parseJSON v@(A.String _) = HoverContentsMS . singleton <$> parseJSON v -- PlainString
  parseJSON v@(A.Array _)  = HoverContentsMS <$> parseJSON v             -- [MarkedString]
  parseJSON v@(A.Object _) = HoverContents   <$> parseJSON v             -- MarkupContent
                         <|> HoverContentsMS . singleton <$> parseJSON v -- CodeString
  parseJSON _ = mempty

where singleton x = List [x]. (I didn't check this code actually works.)

@alanz
Copy link
Collaborator

alanz commented May 7, 2019

Well, according to the spec, a Response message has

	/**
	 * The result of a request. This member is REQUIRED on success.
	 * This member MUST NOT exist if there was an error invoking the method.
	 */
	result?: string | number | boolean | object | null;

So we encode HoverContentsEmpty at the JSON level to be an explicit null value, for when there is no hover result.

That said, the change came about from a request for a student project, so perhaps the clients in the wild do not support this. But I am loathe to remove something that is actually specified to be like this. By my interpretation of the spec.

@bubba ?

@Hogeyama
Copy link
Author

Hogeyama commented May 7, 2019

I think the null value is already encoded as Maybe in HoverRequest and HoverResponse:

type HoverRequest = RequestMessage ClientMethod TextDocumentPositionParams (Maybe Hover)
type HoverResponse = ResponseMessage (Maybe Hover)

In other words, what is the difference between the following result1 and result2?

result1, result2 :: Maybe Hover
result1 = Nothing
result2 = Just (Hover HoverContentsEmpty Nothing)

@alanz
Copy link
Collaborator

alanz commented May 7, 2019

The HoverResponse is encoded for JSON using

lspOptions = defaultOptions { omitNothingFields = True, fieldLabelModifier = drop 1 }

so setting the response to Nothing omits the field completely.

This is different from explicitly encoding it as contents: null, which the spec allows.

@Hogeyama
Copy link
Author

Hogeyama commented May 7, 2019

No, it isn't. Because ResponseMessage is defined as follows,

data ResponseMessage a =
  ResponseMessage
    { _jsonrpc :: Text
    , _id      :: LspIdRsp
    , _result  :: Maybe a
    , _error   :: Maybe ResponseError
    } deriving (Read,Show,Eq)
deriveJSON lspOptions ''ResponseMessage

HoverResponse has nested Maybe:

type HoverResponse
  = ResponseMessage
    { _jsonrpc :: Text
    , _id      :: LspIdRsp
    , _result  :: Maybe (Maybe Hover)
    , _error   :: Maybe ResponseError
    }

So, Core.makeResponseMessage req result1 is a record like

ResponseMessage
  { _jsonrpc = "2.0"
  , _id      = 1
  , _result  = Just Nothing
  , _error   = Nothing
  }

and encoded into the following json

{"jsonrpc":"2.0","id":1,"result":null}

Indeed, hie has sent above message until this commit.

By the way, contents: null is a typo of result: null?

@alanz
Copy link
Collaborator

alanz commented May 7, 2019

Yes, it was a typo, I meant result.

I will sort this out soon, I am in the midst of another PR, don't want to do two things in one.

@lukel97
Copy link
Collaborator

lukel97 commented May 7, 2019

@alanz @Hogeyama makes sense to me to drop that constructor. Nulls are indeed the billion dollar mistake

alanz added a commit that referenced this issue May 8, 2019
But keep the `Monoid` instance because it allows `mconcat`

Closes #162
@alanz alanz closed this as completed in #166 May 8, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants