orbitalquark / textadept-lsp

Language server protocol client module for Textadept.
MIT License
28 stars 9 forks source link

when sending empty params, ensure the resulting json is an object rather than an array #1

Closed paulmr closed 3 years ago

paulmr commented 3 years ago

While using textadept-lsp with metals, an LSP server for Scala, I was unable to get it to communicate with Textadept.

On viewing the metals logfile, I saw the following error:

WARNING: Issue found in NotificationMessage: Message could not be parsed.
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 51 path $.params

which occured when textadept sent the initialized message.

Indeed, looking at the RPC log in textadept, I can see that it is sending an array for the params field when it is empty (whereas when it is not empty it is an object):

RPC send: {"params":[],"jsonrpc":"2.0","method":"initialized"}

The lsp plugin is creating an empty lua table for the params in this case:

function Server:notify(method, params)
  local message = {jsonrpc = '2.0', method = method, params = params or {}}

but because Lua has the same datastructure for objects and arrays, dkjson defaults to converting the table to an array unless it has a metatable attribute __jsontype to say otherwise:

`<metatable>.__jsontype`
------------------------

`__jsontype` can be either `"array"` or `"object"`. This value is only
checked for empty tables. (The default for empty tables is `"array"`).

A simple way to create a table with such a metatable field is to use json.decode('{}').

The proposed change here does just that. The result is that we send this to the server:

RPC send: {"jsonrpc":"2.0","method":"initialized","params":{}}

which is parsed correctly by metals and after which it then works perfectly.

orbitalquark commented 3 years ago

Thanks for the report. Fixed via https://github.com/orbitalquark/textadept-lsp/commit/d9e8305728dd3ddcebb81f65b1941fe56a38c991.