ionide / FsAutoComplete

F# language server using Language Server Protocol
Other
386 stars 151 forks source link

Improve output of `fsharp/documentation` #436

Open TOTBWF opened 4 years ago

TOTBWF commented 4 years ago

Right now, the output of fsharp/documentation is very ionide specific. For example, consider:

{
  "XmlKey": "M:Microsoft.FSharp.Collections.SeqModule.TryFind``1(Microsoft.FSharp.Core.FSharpFunc{``0,System.Boolean},System.Collections.Generic.IEnumerable{``0})",
  "Constructors": [],
  "Fields": [],
  "Functions": [],
  "Interfaces": [],
  "Attributes": [],
  "Types": [],
  "Signature": "val tryFind: \n   predicate: 'T -> bool ->\n   source   : <a href='command:fsharp.showDocumentation?%5B%7B%20%22XmlDocSig%22%3A%20%22T%3ASystem.Collections.Generic.IEnumerable%601%22%2C%20%22AssemblyName%22%3A%20%22System.Runtime%22%7D%5D'>seq<'T></a>    \n           -> <a href='command:fsharp.showDocumentation?%5B%7B%20%22XmlDocSig%22%3A%20%22T%3AMicrosoft.FSharp.Core.FSharpOption%601%22%2C%20%22AssemblyName%22%3A%20%22FSharp.Core%22%7D%5D'>Option<'T></a>",
  "Comment": "**Description**\n\nReturns the first element for which the given function returns True.\n Return None if no such element exists.\n\n**Parameters**\n\n* `predicate`: A function that evaluates to a Boolean when given an item in the sequence.\n* `source`: The input sequence.\n\n**Returns**\n\nThe found element or None.\n\n**Exceptions**\n\n* `System.ArgumentNullException`: Thrown when the input sequence is null.\n\n**Generic parameters**\n\n* `'T` is `string`",
  "Footer": "Full name: Microsoft.FSharp.Collections.Seq.tryFind\nDeclaring Entity: <a href='command:fsharp.showDocumentation?%5B%7B%20%22XmlDocSig%22%3A%20%22T%3AMicrosoft.FSharp.Collections.SeqModule%22%2C%20%22AssemblyName%22%3A%20%22FSharp.Core%22%7D%5D'>Seq</a>\nAssembly: FSharp.Core"
}

This has a mix of markdown and html in it, as well as ionide specific commands, which makes it rather difficult to consume for other tools. I propose that we make the output a bit more generic by doing something along the lines of

{
  "XmlKey": "M:Microsoft.FSharp.Collections.SeqModule.TryFind``1(Microsoft.FSharp.Core.FSharpFunc{``0,System.Boolean},System.Collections.Generic.IEnumerable{``0})",
  "Constructors": [],
  "Fields": [],
  "Functions": [],
  "Interfaces": [],
  "Attributes": [],
  "Types": [],
  "Signature": {
      "Text" : "val tryFind: \n   predicate: 'T -> bool ->\n   source   : seq<'T> -> \n Option<'T>",
      "Links": [{"Span" : { "Start" : <start position>, "End" : <end position>}, "Link" : "?%5B%7B%20%22XmlDocSig%22%3A%20%22T%3AMicrosoft.FSharp.Collections.SeqModule%22%2C%20%22AssemblyName%22%3A%20%22FSharp.Core%22%7D%5D"}, ...],
   "Comment" : {
      "Description" : "Returns the first element ...",
      "Parameters" : ...,
     ...
   }
}
enricosada commented 4 years ago

Another way, instead of make it more generic, is to support multiple formats in FSAC, based on an initialize config.

like:

so ionide can initialize it as

and others extension can choose based on supported formats.

I think can be easier to maintain it in FSAC, because is easier to render.

Krzysztof-Cieslak commented 4 years ago

Yes, I’d rather go with solution suggested by @enricosada. One of the reasons I went with embedding Ionide specific things into the output was difficulties I had with correct displaying stuff in Panel in Ionide when I’ve attempted more generic approach

enricosada commented 4 years ago

What is a format nice output for:

i think this will be useful also in other places, for rich text output

Having it in FSAC help maintain it when internal structure change. Using just json out may break more and be more complicate to evolve, meanwhile we can handle new types in FSAC when are added (less work for other extensions)

cannorin commented 4 years ago

In Vim it is relatively easy to consume JSON. For texts, plain text is fine since it is hard to handle Markdown nicely (other than displaying it as-is).

enricosada commented 4 years ago

@cannorin i mean, the idea is to format to plaintext too, but if vim has a special way to use stuff like link, bold, etc, we can format like that

TOTBWF commented 4 years ago

Emacs can handle markdown very well, so it's probably the best option on my end.

cannorin commented 4 years ago

afaik helptext is the only format with such functionality

cannorin commented 4 years ago

Any updates on this?

I've found several tools to convert Markdown into helptext:

Maybe we can implement something similar in F# and add it to FSAC? I'm willing to help this if you need a hand.

WillEhrendreich commented 11 months ago

I'd really like this to be changed up too, I am trying to implement putting the output of fsharp/documentationSymbol into the hover request in neovim, I'm thinking of just having it in fold within that window, so both requests get resolved and present info to the user but don't have to be bulky and huge either..

Anyway, right now, as it stands, I'm having to parse out the html command:fsharp.showDocumentation and then map that to the right request and convert the characters and decode it to json then have json turn to a lua table, then have that lua table passed as arguments into creating the params, then turning that into a request like

vim.lsp.buf_request(0,"fsharp/documentationSymbol",
  {
    XmlSig= "M:System.String.Trim", 
    Assembly= "netstandard"
  },
  function(error, result, context, config)
    vim.notify( "handling fsharp/documentationSymbol | result is: \n" .. vim.inspect({ error or "", result or "", context or "", config or "" }))
  end )

due to other issues, this isn't giving me text back from fsac, but when I figure out how to do that, I'll be completing the hover stuff.

It might, however, be easier if it was just passed as markdown to begin with, for most non vscode users. in neovim, the md is dealt with and parsed by tree-sitter, and if you have a link in md, it works to simply open the link by asking for it's hover or definition or something i can't remember off the top of my head.

As it stands it's definitely not exceedingly usable in the current format, and the conditional response formatting based on which editor send the init request sounds reasonable to me, as long as it doesn't explode, of course. fsac choosing from regular md, plaintext, and vscode specific md formatting honestly is probably good for the best compatability for everyone.

WillEhrendreich commented 1 month ago

hey @TheAngryByrd and @baronfel

I'm wondering if there is a way to have https://github.com/ionide/FsAutoComplete/blob/e9ad5ebf7ba65b906352158c2b2ec8da19539e8c/src/FsAutoComplete.Core/DocumentationFormatter.fs#L44

switch it's output based on what client gets sent to the server?

on it being anything other than VSCode, this is not a useful output.

I want it just to send like.. file urls or.. straight up documentation.. or.. whatever that isn't a vscode only link. lol.

Ideally it formatting stuff in a general enough way for any client to reasonably display it in hover would be great, but even if i have to write a custom handler only for my Ionide-nvim, I'm still willing to do that, and maybe @cannorin can put it in the official one.

I can whittle down a full verbose response after it gets into neovim, perhaps, or if there is a surefire way to get it to look up the same info Ionide vscode is going to be grabbing, then great.. but.. do you have any suggestions about starting this process?