diff --git a/package.json b/package.json index bfa02223..400acc31 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "fable-loader": "1.0.7", "fable-utils": "^1.0.2", "mocha": "*", + "showdown": "^1.9.0", "toml": "*", "vscode": "*", "webpack": "^3.5.5", diff --git a/paket.dependencies b/paket.dependencies index 102a4fbd..71c43281 100644 --- a/paket.dependencies +++ b/paket.dependencies @@ -21,6 +21,7 @@ github ionide/ionide-vscode-helpers src/Fable.Import.VSCode.fs github ionide/ionide-vscode-helpers src/Helpers.fs github ionide/ionide-vscode-helpers src/Fable.Import.Axios.fs github ionide/ionide-vscode-helpers src/Fable.Import.ws.fs +github ionide/ionide-vscode-helpers src/Fable.Import.Showdown.fs group build source https://www.nuget.org/api/v2 diff --git a/paket.lock b/paket.lock index ede4c79a..e734edab 100644 --- a/paket.lock +++ b/paket.lock @@ -39,7 +39,7 @@ NUGET System.Runtime.Loader (>= 4.0) - restriction: && (< net461) (>= netstandard2.0) System.Security.Cryptography.Algorithms (>= 4.3) - restriction: && (< net461) (>= netstandard2.0) FSharp.Core (4.6.2) - restriction: >= netstandard1.6 - Microsoft.NETCore.App (2.2.3) - restriction: >= netcoreapp2.0 + Microsoft.NETCore.App (2.2.4) - restriction: >= netcoreapp2.0 Microsoft.NETCore.Platforms (2.2) - restriction: || (&& (>= net45) (< netstandard1.3) (>= netstandard1.6)) (&& (< net45) (< netstandard1.2) (>= netstandard1.6) (< win8)) (&& (< net45) (< netstandard1.3) (>= netstandard1.6) (< win8) (< wpa81)) (&& (< net45) (< netstandard1.4) (>= netstandard1.6) (< win8) (< wpa81)) (&& (< net45) (< netstandard1.5) (>= netstandard1.6) (< win8) (< wpa81)) (&& (< net45) (>= netstandard1.6) (< netstandard2.0) (< win8) (< wpa81)) (&& (< net45) (>= netstandard2.0)) (&& (>= net46) (< netstandard1.4) (>= netstandard1.6)) (&& (>= net461) (>= netstandard1.6)) (>= netcoreapp2.0) (&& (< netstandard1.0) (>= netstandard1.6) (< portable-net45+win8)) (&& (< netstandard1.0) (>= netstandard1.6) (>= win8)) (&& (< netstandard1.0) (>= netstandard1.6) (< win8)) (&& (< netstandard1.3) (>= netstandard1.6) (< win8) (>= wpa81)) (&& (< netstandard1.5) (>= netstandard1.6) (>= uap10.0)) (&& (>= netstandard1.6) (< portable-net45+win8+wpa81)) (&& (>= netstandard1.6) (>= uap10.1)) (&& (>= netstandard1.6) (>= wp8)) Microsoft.NETCore.Targets (2.1) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.6) (< netstandard2.0) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (< netstandard1.2) (>= netstandard1.6) (< win8)) (&& (< monoandroid) (< net45) (< netstandard1.3) (>= netstandard1.6) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (< netstandard1.4) (>= netstandard1.6) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (< netstandard1.5) (>= netstandard1.6) (< win8) (< wpa81)) (&& (< netstandard1.2) (>= netstandard1.6) (>= uap10.0) (< win8)) (&& (< netstandard1.3) (>= netstandard1.6) (>= uap10.0) (< win8) (< wpa81)) (&& (< netstandard1.5) (>= netstandard1.6) (>= uap10.0) (< win8) (< wpa81)) (&& (>= netstandard1.6) (< portable-net45+win8+wp8+wpa81)) (&& (>= netstandard1.6) (< portable-net45+win8+wpa81)) Microsoft.Win32.Primitives (4.3) - restriction: || (&& (< net45) (< netstandard1.4) (>= netstandard1.6) (< win8) (< wpa81)) (&& (< net45) (< netstandard1.5) (>= netstandard1.6) (< win8) (< wpa81)) (&& (< net45) (>= netstandard1.6) (< netstandard2.0) (< win8) (< wpa81)) (&& (>= net46) (< netstandard1.4) (>= netstandard1.6)) (>= netcoreapp2.0) (&& (< netstandard1.5) (>= netstandard1.6) (>= uap10.0)) @@ -95,7 +95,7 @@ NUGET System.Threading.Timer (>= 4.3) - restriction: || (&& (< net45) (>= netstandard1.2) (< netstandard1.3) (< win8) (< wpa81)) (&& (< net45) (>= netstandard1.3) (< netstandard1.4) (< win8) (< wpa81)) (&& (< net45) (>= netstandard1.4) (< netstandard1.5) (< win8) (< wpa81)) (&& (< net45) (>= netstandard1.5) (< netstandard1.6) (< win8) (< wpa81)) (&& (< net45) (>= netstandard1.6) (< netstandard2.0) (< win8) (< wpa81)) (&& (< netstandard1.5) (>= uap10.0) (< uap10.1)) System.Xml.ReaderWriter (>= 4.3) - restriction: || (&& (< net45) (>= netstandard1.1) (< netstandard1.2) (< win8)) (&& (< net45) (>= netstandard1.2) (< netstandard1.3) (< win8) (< wpa81)) (&& (< net45) (>= netstandard1.3) (< netstandard1.4) (< win8) (< wpa81)) (&& (< net45) (>= netstandard1.4) (< netstandard1.5) (< win8) (< wpa81)) (&& (< net45) (>= netstandard1.5) (< netstandard1.6) (< win8) (< wpa81)) (&& (< net45) (>= netstandard1.6) (< netstandard2.0) (< win8) (< wpa81)) (&& (>= net46) (< netstandard1.4)) (&& (>= netstandard1.0) (< portable-net45+win8+wpa81) (< wp8)) (&& (< netstandard1.5) (>= uap10.0) (< uap10.1)) System.Xml.XDocument (>= 4.3) - restriction: || (&& (< net45) (>= netstandard1.1) (< netstandard1.2) (< win8)) (&& (< net45) (>= netstandard1.2) (< netstandard1.3) (< win8) (< wpa81)) (&& (< net45) (>= netstandard1.3) (< netstandard1.4) (< win8) (< wpa81)) (&& (< net45) (>= netstandard1.4) (< netstandard1.5) (< win8) (< wpa81)) (&& (< net45) (>= netstandard1.5) (< netstandard1.6) (< win8) (< wpa81)) (&& (< net45) (>= netstandard1.6) (< netstandard2.0) (< win8) (< wpa81)) (&& (>= netstandard1.0) (< portable-net45+win8+wpa81) (< wp8)) (&& (< netstandard1.5) (>= uap10.0) (< uap10.1)) - Newtonsoft.Json (12.0.1) - restriction: >= netcoreapp2.0 + Newtonsoft.Json (12.0.2) - restriction: >= netcoreapp2.0 runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.6) (< netstandard2.0) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (< netstandard1.2) (>= netstandard1.6) (< win8)) (&& (< monoandroid) (< net45) (< netstandard1.3) (>= netstandard1.6) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (< netstandard1.4) (>= netstandard1.6) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (< netstandard1.5) (>= netstandard1.6) (< win8) (< wpa81)) (&& (< net45) (>= net46) (< netstandard1.4) (>= netstandard1.6)) (&& (< netstandard1.5) (>= netstandard1.6) (>= uap10.0)) runtime.debian.9-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.6) (< netstandard2.0) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (< netstandard1.2) (>= netstandard1.6) (< win8)) (&& (< monoandroid) (< net45) (< netstandard1.3) (>= netstandard1.6) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (< netstandard1.4) (>= netstandard1.6) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (< netstandard1.5) (>= netstandard1.6) (< win8) (< wpa81)) (&& (< net45) (>= net46) (< netstandard1.4) (>= netstandard1.6)) (&& (< netstandard1.5) (>= netstandard1.6) (>= uap10.0)) runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.6) (< netstandard2.0) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (< netstandard1.2) (>= netstandard1.6) (< win8)) (&& (< monoandroid) (< net45) (< netstandard1.3) (>= netstandard1.6) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (< netstandard1.4) (>= netstandard1.6) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (< netstandard1.5) (>= netstandard1.6) (< win8) (< wpa81)) (&& (< net45) (>= net46) (< netstandard1.4) (>= netstandard1.6)) (&& (< netstandard1.5) (>= netstandard1.6) (>= uap10.0)) @@ -604,10 +604,10 @@ NUGET FSharp.Core (>= 4.3.4) - restriction: >= netstandard2.0 GIT remote: https://github.com/fsharp/FsAutoComplete.git - (630b6935b7913e7e126b1843235123b62906ca03) + (c9636b287d0c51b49ab4d0528e36f40392ddaf2b) build: build.cmd LocalRelease os: windows - (630b6935b7913e7e126b1843235123b62906ca03) + (c9636b287d0c51b49ab4d0528e36f40392ddaf2b) build: build.sh LocalRelease os: mono remote: https://github.com/fsharp-editing/Forge.git @@ -618,13 +618,14 @@ GIT build: build.sh Build os: mono remote: https://github.com/ionide/ionide-fsgrammar.git - (942f1a311f84a402cb397d7a9f2bc17e630f8834) + (b2100c95d7857c5421d111a860fcdd20954a0263) GITHUB remote: ionide/ionide-vscode-helpers - src/Fable.Import.Axios.fs (50c364c2e88acc2fec7094bfd3be0973cb2826aa) - src/Fable.Import.VSCode.fs (50c364c2e88acc2fec7094bfd3be0973cb2826aa) - src/Fable.Import.ws.fs (50c364c2e88acc2fec7094bfd3be0973cb2826aa) - src/Helpers.fs (50c364c2e88acc2fec7094bfd3be0973cb2826aa) + src/Fable.Import.Axios.fs (af96a42db5a5f518d66c50f46ad903955360028e) + src/Fable.Import.Showdown.fs (af96a42db5a5f518d66c50f46ad903955360028e) + src/Fable.Import.VSCode.fs (af96a42db5a5f518d66c50f46ad903955360028e) + src/Fable.Import.ws.fs (af96a42db5a5f518d66c50f46ad903955360028e) + src/Helpers.fs (af96a42db5a5f518d66c50f46ad903955360028e) GROUP build NUGET remote: https://www.nuget.org/api/v2 @@ -1140,5 +1141,5 @@ NUGET System.Xml.ReaderWriter (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.3) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.3) (< win8) (< wp8) (< wpa81)) (< portable-net45+win8+wp8+wpa81) GITHUB remote: fsharp/FAKE - modules/Octokit/Octokit.fsx (22668d1c0dbb43626c4d2abdc13e9614e8c9d04d) + modules/Octokit/Octokit.fsx (233a5ab4a51f5c6cf7bd2b1972d6bb5cccee9067) Octokit (>= 0.20) \ No newline at end of file diff --git a/release/images/lock-open-solid-light.svg b/release/images/lock-open-solid-light.svg new file mode 100644 index 00000000..f6c6d528 --- /dev/null +++ b/release/images/lock-open-solid-light.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/release/images/lock-open-solid.svg b/release/images/lock-open-solid.svg new file mode 100644 index 00000000..270e7ca5 --- /dev/null +++ b/release/images/lock-open-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/release/images/lock-solid-light.svg b/release/images/lock-solid-light.svg new file mode 100644 index 00000000..3ed55f75 --- /dev/null +++ b/release/images/lock-solid-light.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/release/images/lock-solid.svg b/release/images/lock-solid.svg new file mode 100644 index 00000000..d1c921d8 --- /dev/null +++ b/release/images/lock-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/release/package.json b/release/package.json index 17778c96..8cd07ecf 100644 --- a/release/package.json +++ b/release/package.json @@ -422,13 +422,47 @@ }, { "command": "fsharp.revealInSolutionExplorer", - "title": "F#: Reveal in solution explorer", + "title": "Reveal in solution explorer", "category": "F#", "icon": { "light": "./images/auto-reveal-light.svg", "dark": "./images/auto-reveal-dark.svg" } - } + }, + { + "command": "fsharp.openInfoPanel", + "title": "Open Info Panel", + "description": "Opens Info Panel displaying documentation", + "category": "F#" + }, + { + "command": "fsharp.updateInfoPanel", + "title": "Update Info Panel", + "description": "Updates Info Panel with documentation of current symbol", + "category": "F#" + }, + { + "command": "fsharp.showDocumentation", + "title": "Show Documentation for given symbol" + }, + { + "command": "fsharp.openInfoPanel.lock", + "title": "Lock Info Panel", + "category": "F#", + "icon": { + "light": "./images/lock-solid-light.svg", + "dark": "./images/lock-solid.svg" + } + }, + { + "command": "fsharp.openInfoPanel.unlock", + "title": "Unlock Info Panel", + "category": "F#", + "icon": { + "light": "./images/lock-open-solid-light.svg", + "dark": "./images/lock-open-solid.svg" + } + } ], "viewsContainers": { "activitybar": [ @@ -633,6 +667,10 @@ { "command": "MSBuild.cleanCurrent", "when": "editorLangId == 'fsharp'" + }, + { + "command": "fsharp.showDocumentation", + "when": "false" } ], "view/title": [ @@ -998,6 +1036,16 @@ "command": "fsharp.scriptrunner.run", "when": "editorLangId == 'fsharp' && resourceExtname == '.fsx'", "group": "navigation" + }, + { + "command": "fsharp.openInfoPanel.unlock", + "when": "infoPanelFocused && infoPanelLocked", + "group": "navigation" + }, + { + "command": "fsharp.openInfoPanel.lock", + "when": "infoPanelFocused && !infoPanelLocked", + "group": "navigation" } ], "touchBar": [ @@ -1060,6 +1108,16 @@ "command": "MSBuild.buildCurrentSolution", "key": "ctrl+alt+shift+b", "when": "fsharp.project.any" + }, + { + "command": "fsharp.openInfoPanel", + "key": "alt+,", + "when": "editorFocus && editorLangId == 'fsharp'" + }, + { + "command": "fsharp.updateInfoPanel", + "key": "alt+.", + "when": "editorFocus && editorLangId == 'fsharp'" } ], "configurationDefaults": { @@ -1348,6 +1406,32 @@ "type": "boolean", "default": false, "description": "Enables smart indent feature" + }, + "FSharp.infoPanelUpdate": { + "type": "string", + "description": "Controls when the info panel is updated", + "enum": [ + "onCursorMove", + "onHover", + "both", + "none" + ], + "default": "onCursorMove" + }, + "FSharp.infoPanelReplaceHover": { + "type": "boolean", + "description": "Controls whether the info panel replaces tooltips", + "default": false + }, + "FSharp.infoPanelStartLocked": { + "type": "boolean", + "description": "Controls whether the info panel should be locked at startup", + "default": false + }, + "FSharp.infoPanelShowOnStartup": { + "type": "boolean", + "description": "Controls whether the info panel should be displayed at startup", + "default": false } } }, diff --git a/src/Components/InfoPanel.fs b/src/Components/InfoPanel.fs new file mode 100644 index 00000000..e60e08bb --- /dev/null +++ b/src/Components/InfoPanel.fs @@ -0,0 +1,305 @@ +namespace Ionide.VSCode.FSharp + +open System +open Fable.Core +open Fable.Core.JsInterop +open Fable.Import +open Fable.Import.vscode +open Fable.Import.Node +open Ionide.VSCode.Helpers +open DTO +open Fable +open Fable.Import.vscode +module node = Fable.Import.Node.Exports + +module InfoPanel = + + module Panel = + + let showdown = Fable.Import.Showdown.showdown.Converter.Create() + + let mutable panel : WebviewPanel option = None + + let mutable locked = false + + let private isFsharpTextEditor (textEditor : TextEditor) = + if JS.isDefined textEditor && JS.isDefined textEditor.document then + let doc = textEditor.document + match doc with + | Document.FSharp -> true + | _ -> false + else + false + + + let setContent str = + panel |> Option.iter (fun p -> + let str = showdown.makeHtml str + let str = + sprintf """ + +
+ + + + %s + + + """ str + + p.webview.html <- str + ) + + let clear () = panel |> Option.iter (fun p -> p.webview.html <- "") + + let mapContent res = + if isNotNull res then + let res = (res.Data |> Array.concat).[0] + + let fsharpBlock lines = + let cnt = (lines |> String.concat "\n") + if String.IsNullOrWhiteSpace cnt then "" + else sprintf "\n%s\n" cnt + + let sigContent = + let lines = + res.Signature + |> String.split [|'\n'|] + |> Array.filter (not << String.IsNullOrWhiteSpace) + + match lines |> Array.splitAt (lines.Length - 1) with + | (h, [| StartsWith "Full name:" fullName |]) -> + [| yield fsharpBlock h + yield "*" + fullName + "*" |] + | _ -> [| fsharpBlock lines |] + |> String.concat "\n" + + let commentContent = + res.Comment + |> Markdown.createCommentString + + let footerContent = + res.Footer + |> String.split [|'\n' |] + |> Array.filter (not << String.IsNullOrWhiteSpace) + |> Array.map (fun n -> "*" + n + "*") + |> String.concat "\n\n" + + let ctors = + res.Constructors + |> List.filter (not << String.IsNullOrWhiteSpace) + |> List.distinct + |> fsharpBlock + + let intfs = + res.Interfaces + |> List.filter (not << String.IsNullOrWhiteSpace) + |> List.distinct + |> List.sort + |> fsharpBlock + + let attrs = + res.Attributes + |> List.filter (not << String.IsNullOrWhiteSpace) + |> List.distinct + |> List.sort + |> fsharpBlock + + let fncs = + res.Functions + |> List.filter (not << String.IsNullOrWhiteSpace) + |> List.distinct + |> fsharpBlock + + let fields = + res.Fields + |> List.filter (not << String.IsNullOrWhiteSpace) + |> List.distinct + |> fsharpBlock + + let res = + [| + yield sigContent + if not (String.IsNullOrWhiteSpace commentContent) then + yield "---" + yield commentContent + yield "\n" + if not (String.IsNullOrWhiteSpace attrs) then + yield "---" + yield "#### Attributes" + yield attrs + yield "\n" + if not (String.IsNullOrWhiteSpace intfs) then + yield "---" + yield "#### Implemented Interfaces" + yield intfs + yield "\n" + if not (String.IsNullOrWhiteSpace ctors) then + yield "---" + yield "#### Constructors" + yield ctors + yield "\n" + if not (String.IsNullOrWhiteSpace fncs) then + yield "---" + yield "#### Functions" + yield fncs + yield "\n" + if not (String.IsNullOrWhiteSpace fields) then + yield "---" + yield "#### Fields" + yield fields + yield "\n" + if not (String.IsNullOrWhiteSpace footerContent) then + yield "---" + yield (footerContent) + + |] |> String.concat "\n" + Some res + else + None + + let update (textEditor : TextEditor) (selections : ResizeArray