-
Notifications
You must be signed in to change notification settings - Fork 833
port fsih to fsi as a hash directive #17140
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
Merged
+1,117
−461
Merged
Changes from all commits
Commits
Show all changes
45 commits
Select commit
Hold shift + click to select a range
b52972e
port fsih to fsi as a hash directive
dawedawe 6a14c98
add PR number
dawedawe 01d8ded
update xlf files
dawedawe a8b39e9
update core printing baselines
dawedawe 42f479d
rename module to FsiHelp
dawedawe 909913c
rewrite Help.Print() to return a string to be independent of FsiConso…
dawedawe d3c4daf
move fsihelp module to dedicated file
dawedawe cea11e9
use shims for the filesystem
dawedawe 6c38121
- Use fsi.h as an user interface.
dawedawe fdbedae
use a fsi printer for nicer output
dawedawe a7a2d4a
update baselines
dawedawe c0e6bcd
remove suppressItPrint parameter
dawedawe c063b89
Update src/FSharp.Compiler.Interactive.Settings/fsihelp.fs
dawedawe db6a446
Update src/FSharp.Compiler.Interactive.Settings/fsihelp.fs
dawedawe c8994eb
use voption to let the printer work in the (v)none case
dawedawe 9f7203f
format
dawedawe d605fd8
remove doubled assembly attributes
dawedawe eacde80
refactor
dawedawe 37506de
Merge branch 'main' into port_fsih_to_fsi
dawedawe cbc2d99
add some tests
dawedawe 46f8844
- let xpath queries work with single quotes in names like "shouldn't"
dawedawe 6a5aa1b
Merge branch 'main' into port_fsih_to_fsi
dawedawe 65bb24c
Merge branch 'main' into port_fsih_to_fsi
dawedawe af88e74
Trigger Build
dawedawe dcfe6b7
Merge branch 'main' into port_fsih_to_fsi
dawedawe 0689e5c
adjust changelog entry
dawedawe 1bded2a
Merge branch 'main' into port_fsih_to_fsi
dawedawe a48ca3d
Merge branch 'main' into port_fsih_to_fsi
dawedawe dbc32e4
Merge branch 'main' into port_fsih_to_fsi
dawedawe 3b330d6
Merge branch 'main' into port_fsih_to_fsi
dawedawe ddf9b0e
Merge branch 'main' into port_fsih_to_fsi
dawedawe 4631ac2
move back to #h interface
dawedawe c6a511f
rename tryGetDocumentation to tryGetHelp
dawedawe e8db338
use #help "expr";;
dawedawe 9f7fa7a
append a newline if we don't find docs to position cursor correctly
dawedawe ef5d1a3
format
dawedawe 72071c9
adjust release notes again
dawedawe 35392f4
update surfacearea baselines
dawedawe 11b00f2
Merge branch 'main' into port_fsih_to_fsi
dawedawe e12ae7f
adjust help text to use "identifier" instead of "expression"
dawedawe 6894681
add unit test for non-identifier to show unhappy path
dawedawe c13ca67
add bsl entries for help output inside of fsi
dawedawe 29b3ad6
update line numbers in bsl files
dawedawe 1c238b5
Merge branch 'main' into port_fsih_to_fsi
KevinRansom 01fbdf2
update line numbers in err bsl files
dawedawe File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,272 @@ | ||
| module FSharp.Compiler.Interactive.FsiHelp | ||
|
|
||
| [<assembly: System.Runtime.InteropServices.ComVisible(false)>] | ||
| [<assembly: System.CLSCompliant(true)>] | ||
| do () | ||
|
|
||
| open System | ||
| open System.Collections.Generic | ||
| open System.IO | ||
| open System.Text | ||
| open System.Reflection | ||
| open FSharp.Compiler.IO | ||
|
|
||
| module Parser = | ||
|
|
||
| open System.Xml | ||
|
|
||
| type Help = | ||
| { | ||
| Summary: string | ||
| Remarks: string option | ||
| Parameters: (string * string) list | ||
| Returns: string option | ||
| Exceptions: (string * string) list | ||
| Examples: (string * string) list | ||
| FullName: string | ||
| Assembly: string | ||
| } | ||
|
|
||
| member this.ToDisplayString() = | ||
| let sb = StringBuilder() | ||
|
|
||
| let parameters = | ||
| this.Parameters | ||
| |> List.map (fun (name, description) -> sprintf "- %s: %s" name description) | ||
| |> String.concat "\n" | ||
|
|
||
| sb.AppendLine().AppendLine("Description:").AppendLine(this.Summary) |> ignore | ||
|
|
||
| match this.Remarks with | ||
| | Some r -> sb.AppendLine $"\nRemarks:\n%s{r}" |> ignore | ||
| | None -> () | ||
|
|
||
| if not (String.IsNullOrWhiteSpace(parameters)) then | ||
| sb.AppendLine $"\nParameters:\n%s{parameters}" |> ignore | ||
|
|
||
| match this.Returns with | ||
| | Some r -> sb.AppendLine $"Returns:\n%s{r}" |> ignore | ||
| | None -> () | ||
|
|
||
| if not this.Exceptions.IsEmpty then | ||
| sb.AppendLine "\nExceptions:" |> ignore | ||
|
|
||
| for (exType, exDesc) in this.Exceptions do | ||
| sb.AppendLine $"%s{exType}: %s{exDesc}" |> ignore | ||
|
|
||
| if not this.Examples.IsEmpty then | ||
| sb.AppendLine "\nExamples:" |> ignore | ||
|
|
||
| for example, desc in this.Examples do | ||
| sb.AppendLine example |> ignore | ||
|
|
||
| if not (String.IsNullOrWhiteSpace(desc)) then | ||
| sb.AppendLine $"""// {desc.Replace("\n", "\n// ")}""" |> ignore | ||
|
|
||
| sb.AppendLine "" |> ignore | ||
|
|
||
| sb.AppendLine $"Full name: %s{this.FullName}" |> ignore | ||
| sb.AppendLine $"Assembly: %s{this.Assembly}" |> ignore | ||
|
|
||
| sb.ToString() | ||
|
|
||
| let cleanupXmlContent (s: string) = s.Replace("\n ", "\n").Trim() // some stray whitespace from the XML | ||
|
|
||
| // remove any leading `X:` and trailing `N | ||
| let trimDotNet (s: string) = | ||
| let s = if s.Length > 2 && s[1] = ':' then s.Substring(2) else s | ||
| let idx = s.IndexOf('`') | ||
| let s = if idx > 0 then s.Substring(0, idx) else s | ||
| s | ||
|
|
||
| let xmlDocCache = Dictionary<string, string>() | ||
|
|
||
| let tryGetXmlDocument xmlPath = | ||
| try | ||
| match xmlDocCache.TryGetValue(xmlPath) with | ||
| | true, value -> | ||
| let xmlDocument = XmlDocument() | ||
| xmlDocument.LoadXml(value) | ||
| Some xmlDocument | ||
| | _ -> | ||
| use stream = FileSystem.OpenFileForReadShim(xmlPath) | ||
| let rawXml = stream.ReadAllText() | ||
| let xmlDocument = XmlDocument() | ||
| xmlDocument.LoadXml(rawXml) | ||
| xmlDocCache.Add(xmlPath, rawXml) | ||
| Some xmlDocument | ||
| with _ -> | ||
| None | ||
|
|
||
| let getTexts (node: Xml.XmlNode) = | ||
| seq { | ||
| for child in node.ChildNodes do | ||
| if child.Name = "#text" then | ||
| yield child.Value | ||
|
|
||
| if child.Name = "c" then | ||
| yield child.InnerText | ||
|
|
||
| if child.Name = "see" then | ||
| let cref = child.Attributes.GetNamedItem("cref") | ||
|
|
||
| if not (isNull cref) then | ||
| yield cref.Value |> trimDotNet | ||
| } | ||
| |> String.concat "" | ||
|
|
||
| let tryMkHelp (xmlDocument: XmlDocument option) (assembly: string) (modName: string) (implName: string) (sourceName: string) = | ||
| let sourceName = sourceName.Replace('.', '#') // for .ctor | ||
| let implName = implName.Replace('.', '#') // for .ctor | ||
| let xmlName = $"{modName}.{implName}" | ||
|
|
||
| let toTry = | ||
| [ | ||
| $"""/doc/members/member[contains(@name, ":{xmlName}`")]""" | ||
| $"""/doc/members/member[contains(@name, ":{xmlName}(")]""" | ||
| $"""/doc/members/member[contains(@name, ":{xmlName}")]""" | ||
| ] | ||
|
|
||
| xmlDocument | ||
| |> Option.bind (fun xmlDocument -> | ||
| seq { | ||
| for t in toTry do | ||
| let node = xmlDocument.SelectSingleNode(t) | ||
| if not (isNull node) then Some node else None | ||
| } | ||
| |> Seq.tryPick id) | ||
| |> function | ||
| | None -> ValueNone | ||
| | Some n -> | ||
| let summary = | ||
| n.SelectSingleNode("summary") | ||
| |> Option.ofObj | ||
| |> Option.map getTexts | ||
| |> Option.map cleanupXmlContent | ||
|
|
||
| let remarks = | ||
| n.SelectSingleNode("remarks") | ||
| |> Option.ofObj | ||
| |> Option.map getTexts | ||
| |> Option.map cleanupXmlContent | ||
|
|
||
| let parameters = | ||
| n.SelectNodes("param") | ||
| |> Seq.cast<XmlNode> | ||
| |> Seq.map (fun n -> n.Attributes.GetNamedItem("name").Value.Trim(), n.InnerText.Trim()) | ||
| |> List.ofSeq | ||
|
|
||
| let returns = | ||
| n.SelectSingleNode("returns") | ||
| |> Option.ofObj | ||
| |> Option.map (fun n -> getTexts(n).Trim()) | ||
|
|
||
| let exceptions = | ||
| n.SelectNodes("exception") | ||
| |> Seq.cast<XmlNode> | ||
| |> Seq.map (fun n -> | ||
| let exType = n.Attributes.GetNamedItem("cref").Value | ||
| let idx = exType.IndexOf(':') | ||
| let exType = if idx >= 0 then exType.Substring(idx + 1) else exType | ||
| exType.Trim(), n.InnerText.Trim()) | ||
| |> List.ofSeq | ||
|
|
||
| let examples = | ||
| n.SelectNodes("example") | ||
| |> Seq.cast<XmlNode> | ||
| |> Seq.map (fun n -> | ||
| let codeNode = n.SelectSingleNode("code") | ||
|
|
||
| let code = | ||
| if isNull codeNode then | ||
| "" | ||
| else | ||
| n.RemoveChild(codeNode) |> ignore | ||
| cleanupXmlContent codeNode.InnerText | ||
|
|
||
| code, cleanupXmlContent n.InnerText) | ||
| |> List.ofSeq | ||
|
|
||
| match summary with | ||
| | Some s -> | ||
| { | ||
| Summary = s | ||
| Remarks = remarks | ||
| Parameters = parameters | ||
| Returns = returns | ||
| Exceptions = exceptions | ||
| Examples = examples | ||
| FullName = $"{modName}.{sourceName}" // the long ident as users see it | ||
| Assembly = assembly | ||
| } | ||
| |> ValueSome | ||
| | None -> ValueNone | ||
|
|
||
| module Expr = | ||
|
|
||
| open Microsoft.FSharp.Quotations.Patterns | ||
|
|
||
| let tryGetSourceName (methodInfo: MethodInfo) = | ||
| try | ||
| let attr = methodInfo.GetCustomAttribute<CompilationSourceNameAttribute>() | ||
| Some attr.SourceName | ||
| with _ -> | ||
| None | ||
|
|
||
| let getInfos (declaringType: Type) (sourceName: string option) (implName: string) = | ||
| let xmlPath = Path.ChangeExtension(declaringType.Assembly.Location, ".xml") | ||
| let xmlDoc = Parser.tryGetXmlDocument xmlPath | ||
| let assembly = Path.GetFileName(declaringType.Assembly.Location) | ||
|
|
||
| // for FullName cases like Microsoft.FSharp.Core.FSharpOption`1[System.Object] | ||
| let fullName = | ||
| let idx = declaringType.FullName.IndexOf('[') | ||
|
|
||
| if idx >= 0 then | ||
| declaringType.FullName.Substring(0, idx) | ||
| else | ||
| declaringType.FullName | ||
|
|
||
| let fullName = fullName.Replace('+', '.') // for FullName cases like Microsoft.FSharp.Collections.ArrayModule+Parallel | ||
|
|
||
| (xmlDoc, assembly, fullName, implName, sourceName |> Option.defaultValue implName) | ||
|
|
||
| let rec exprNames expr = | ||
| match expr with | ||
| | Call(exprOpt, methodInfo, _exprList) -> | ||
| match exprOpt with | ||
| | Some _ -> None | ||
| | None -> | ||
| let sourceName = tryGetSourceName methodInfo | ||
| getInfos methodInfo.DeclaringType sourceName methodInfo.Name |> Some | ||
| | Lambda(_param, body) -> exprNames body | ||
| | Let(_, _, body) -> exprNames body | ||
| | Value(_o, t) -> getInfos t (Some t.Name) t.Name |> Some | ||
| | DefaultValue t -> getInfos t (Some t.Name) t.Name |> Some | ||
| | PropertyGet(_o, info, _) -> getInfos info.DeclaringType (Some info.Name) info.Name |> Some | ||
| | NewUnionCase(info, _exprList) -> getInfos info.DeclaringType (Some info.Name) info.Name |> Some | ||
| | NewObject(ctorInfo, _e) -> getInfos ctorInfo.DeclaringType (Some ctorInfo.Name) ctorInfo.Name |> Some | ||
| | NewArray(t, _exprs) -> getInfos t (Some t.Name) t.Name |> Some | ||
| | NewTuple _ -> | ||
| let ty = typeof<_ * _> | ||
| getInfos ty (Some ty.Name) ty.Name |> Some | ||
| | NewStructTuple _ -> | ||
| let ty = typeof<struct (_ * _)> | ||
| getInfos ty (Some ty.Name) ty.Name |> Some | ||
| | _ -> None | ||
|
|
||
| module Logic = | ||
|
|
||
| open Expr | ||
| open Parser | ||
|
|
||
| module Quoted = | ||
| let tryGetHelp (expr: Quotations.Expr) = | ||
| match exprNames expr with | ||
| | Some(xmlDocument, assembly, modName, implName, sourceName) -> tryMkHelp xmlDocument assembly modName implName sourceName | ||
| | _ -> ValueNone | ||
|
|
||
| let h (expr: Quotations.Expr) = | ||
| match tryGetHelp expr with | ||
| | ValueNone -> "unable to get documentation\n" | ||
| | ValueSome d -> d.ToDisplayString() | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.