scalameta / metals

Scala language server with rich IDE features 🚀
https://scalameta.org/metals/
Apache License 2.0
2.06k stars 320 forks source link

Synthetic information can't render Sublime links correctly #4406

Open ssahayam-zd opened 1 year ago

ssahayam-zd commented 1 year ago

Issue

When rendering synthetic parameters the sublime action links are not correctly rendered as per the image below

sublime-synthetics

Sublime Text: Build 4126 Metals: 0.11.7 LSP Metals: v0.16.1 Sublime LSP: v1.18.0 Macos: 12.5.1

Metals Settings:

{
    "server_version": "0.11.7",

    "initializationOptions": {
      "didFocusProvider": true,
      "executeClientCommandProvider": true,
      "statusBarProvider": "on",
      "inputBoxProvider": true,
      // (ST4 only) When enabled, shows worksheet evaluations as Sublime.Phantom instead of code comments.
      "decorationProvider": true,
      // (ST4 only) When enabled, inferred types and implicits are shown as as Sublime.Phantom.
      "inlineDecorationProvider": false,
    },

    "settings": {
      "metals": {
        // (ST4 only) When enabled, each method and variable that can have inferred types has them displayed.
        "showInferredType": true,
        // (ST4 only) When enabled, each method that has implicit arguments has them displayed.
        "showImplicitArguments": true,
        // (ST4 only) When enabled, each place where an implicit method or class is used has it displayed.
        "showImplicitConversionsAndClasses": true,

      //"on", "off", "show-message", "log-message"
       "statusBarProvider": "log-message",
      }
    },

  "server_properties": [
    "-Dmetals.client=sublime",
    // "-Dmetals.loglevel=debug",
    // "-Dmetals.verbose",
    "-Xss128m",
    "-Xms1024m"
  ],  
}

Response with the above data from Metals:

{'contents': {'kind': 'markdown', 'value': '```scala\nprivate val jsonContent: Json\n```\n\n**With synthetics added**:\n```scala\nexpect.eql[[Either](subl:lsp_metals_goto {"parameters": ["scala/package.Either#"]})[[ParsingFailure](subl:lsp_metals_goto {"parameters": ["io/circe/ParsingFailure#"]}), [Json](subl:lsp_metals_goto {"parameters": ["io/circe/Json#"]})]](Right[apply](subl:lsp_metals_goto {"parameters": ["scala/util/Right.apply()."]})[[Nothing](subl:lsp_metals_goto {"parameters": ["scala/Nothing#"]}), [Json](subl:lsp_metals_goto {"parameters": ["io/circe/Json#"]})](jsonContent), resultE)([catsKernelEqForEither](subl:lsp_metals_goto {"parameters": ["cats/kernel/EqInstances#catsKernelEqForEither()."]})([eqParsingFailure](subl:lsp_metals_goto {"parameters": ["io/circe/ParsingFailure.eqParsingFailure."]}), [eqJson](subl:lsp_metals_goto {"parameters": ["io/circe/Json.eqJson."]})), [catsShowForEither](subl:lsp_metals_goto {"parameters": ["cats/Show.catsShowForEither()."]})([showParsingFailure](subl:lsp_metals_goto {"parameters": ["io/circe/ParsingFailure.showParsingFailure."]}), [showJson](subl:lsp_metals_goto {"parameters": ["io/circe/Json.showJson."]})), [apply](subl:lsp_metals_goto {"parameters": ["weaver/SourceLocation.apply()."]})())\n```'}}

It looks like Sublime does not know how to properly render this data or the data sent via metals is incorrect. I can raise this issue in the metals repository if the latter is the case.

ssahayam-zd commented 1 year ago

I found that if I removed the scala syntax section and escaped scala's square brackets to get to something like:

'expect.eql\[[Either](subl:lsp_metals_goto {"parameters": ["scala/package.Either#"]})[[ParsingFailure](subl:lsp_metals_goto {"parameters": ["io/circe/ParsingFailure#"]}), [Json](subl:lsp_metals_goto {"parameters": ["io/circe/Json#"]})]\](Right[apply](subl:lsp_metals_goto {"parameters": ["scala/util/Right.apply()."]})\[[Nothing](subl:lsp_metals_goto {"parameters": ["scala/Nothing#"]}), [Json](subl:lsp_metals_goto {"parameters": ["io/circe/Json#"]})\]'

I could then render it into html:

<p>expect.eql[<a href="subl:lsp_metals_goto {&#x22;parameters&#x22;: [&#x22;scala/package.Either#&#x22;]}">Either</a>[<a href="subl:lsp_metals_goto {&#x22;parameters&#x22;: [&#x22;io/circe/ParsingFailure#&#x22;]}">ParsingFailure</a>, <a href="subl:lsp_metals_goto {&#x22;parameters&#x22;: [&#x22;io/circe/Json#&#x22;]}">Json</a>]](Right<a href="subl:lsp_metals_goto {&#x22;parameters&#x22;: [&#x22;scala/util/Right.apply().&#x22;]}">apply</a>[<a href="subl:lsp_metals_goto {&#x22;parameters&#x22;: [&#x22;scala/Nothing#&#x22;]}">Nothing</a>, <a href="subl:lsp_metals_goto {&#x22;parameters&#x22;: [&#x22;io/circe/Json#&#x22;]}">Json</a>]</p>

Which could then be rendered in a popup:

view.show_popup('<p>expect.eql[<a href="subl:lsp_metals_goto {&#x22;parameters&#x22;: [&#x22;scala/package.Either#&#x22;]}">Either</a>[<a href="subl:lsp_metals_goto {&#x22;parameters&#x22;: [&#x22;io/circe/ParsingFailure#&#x22;]}">ParsingFailure</a>, <a href="subl:lsp_metals_goto {&#x22;parameters&#x22;: [&#x22;io/circe/Json#&#x22;]}">Json</a>]](Right<a href="subl:lsp_metals_goto {&#x22;parameters&#x22;: [&#x22;scala/util/Right.apply().&#x22;]}">apply</a>[<a href="subl:lsp_metals_goto {&#x22;parameters&#x22;: [&#x22;scala/Nothing#&#x22;]}">Nothing</a>, <a href="subl:lsp_metals_goto {&#x22;parameters&#x22;: [&#x22;io/circe/Json#&#x22;]}">Json</a>]</p>', max_width=640, max_height=480)

which rendered reasonably correctly:

sythentics-rerendered

ayoub-benali commented 1 year ago

Thanks for the detailed description @ssahayam-zd, this looks very similar to the issue resolved here: https://github.com/scalameta/metals/pull/3378 basically we might have to actually set flag in Metals for it to send the link the right format.

I am gonna investigate the issue

ssahayam-zd commented 1 year ago

Sounds good! Thanks @ayoub-benali 😄

ayoub-benali commented 1 year ago

Hi @ssahayam-zd I just realized that the issue appears only if inlineDecorationProvider is set to false. It seems metals sends different data depending if inlineDecorationProvider is supported or not. I will check why is that but in general I don't recommend touching the initializationOptions, it is my bad making them available or I should at least better document them.

Any specific reason for disabling inlineDecorationProvider ? is it for the clickable links ?

ssahayam-zd commented 1 year ago

Hey @ayoub-benali ,

As I recall, enabling inlineDecorationProvider lead to a lot of flashing text in the past. It looks like that has been fixed, so I can turn it on and the problem goes away.

I like the popup so I get to choose when I get these hints as opposed to always having them on. Also you loose the clickable links as you mentioned.

ayoub-benali commented 1 year ago

I totally see the benefits of the hover info, especially the clickable links. I did some digging and the problem originates from here: https://github.com/scalameta/metals/blob/main/metals/src/main/scala/scala/meta/internal/decorations/SyntheticsDecorationProvider.scala#L259

For me the markdown returned by metals should escape the successive square brackets, so I recommend creating an issue here: https://github.com/scalameta/metals/issues

ayoub-benali commented 1 year ago

@tgodzik @kpodsiad can you please transfer this issue to Metals repository ? I don't permission to do it

ayoub-benali commented 1 year ago

A potential complement, this might be useful for the server to know how the format the markdown:

'markdown': {'version': '3.2.2', 'parser': 'Python-Markdown'}

It is part of the initialization request