11namespace JetBrains.ReSharper.Plugins.FSharp.Psi.Features.ContextActions
22
33open System.IO
4- open System.Linq
54open System.Text
65open FSharp.Compiler .Symbols
76open JetBrains.Application .UI .PopupLayout
87open JetBrains.ReSharper .Feature .Services .Navigation
9- open JetBrains.ReSharper .Plugins .FSharp .Psi .Parsing
108open JetBrains.ReSharper .Psi .Naming
119open JetBrains.ReSharper .Psi .Tree
1210open JetBrains.DocumentManagers .Transactions .ProjectHostActions .Ordering
@@ -34,7 +32,7 @@ open JetBrains.ReSharper.Resources.Shell
3432type GenerateSignatureFileAction ( dataProvider : FSharpContextActionDataProvider ) =
3533 inherit FSharpContextActionBase( dataProvider)
3634
37- let mkSignatureFile ( fsharpFile : IFSharpFile ) : IFSharpFile =
35+ let mkSignatureFile ( fsharpFile : IFSharpFile ): IFSharpFile =
3836 let factory : IFSharpElementFactory = fsharpFile.CreateElementFactory( extension = FSharpSignatureProjectFileType.FsiExtension)
3937 let signatureFile : IFSharpFile = factory.CreateEmptyFile()
4038 let lineEnding = fsharpFile.GetLineEnding()
@@ -43,72 +41,62 @@ type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider)
4341 let rec createModuleMemberSig ( indentation : int ) ( moduleDecl : IModuleLikeDeclaration ) ( moduleMember : IModuleMember ) : IFSharpTreeNode =
4442 match moduleMember with
4543 | :? ITypeDeclarationGroup as typeGroup ->
46- let sigTypeDeclGroups =
47- // TODO: Update type into and keyword for second IFSharpTypeDeclaration in a group.
48-
44+ // Filter out the IFSharpTypeDeclaration where we support the TypeRepresentation for now.
45+ let supportedTypeDeclarations =
4946 typeGroup.TypeDeclarations
5047 |> Seq.choose ( function
5148 | :? IFSharpTypeDeclaration as typeDecl ->
52- // TODO: update and keyword
53- (*
54- ModificationUtil.ReplaceChild(
55- sigTypeGroup.TypeDeclarations.[1].TypeKeyword,
56- (FSharpTokenType.AND.CreateLeafElement()))
57- *)
58-
59- // Resharper implementation
60- //typeDecl.MemberDeclarations
61-
62- // Untyped tree like
63- // typeDecl.TypeMembers
64- let sigMembers =
65- typeDecl.TypeMembers
66- |> Seq.choose ( createMemberDeclaration >> Option.ofObj)
67-
6849 match typeDecl.TypeRepresentation with
69- // TODO: checkout delegates
70- | :? ITypeAbbreviationRepresentation as abbr ->
71- let sigTypeGroup = factory.CreateModuleMember( $" type {getName typeDecl} = int" )
72- match sigTypeGroup with
73- | :? ITypeDeclarationGroup as sigTypeGroup ->
74- let sigDecl = sigTypeGroup.TypeDeclarations.[ 0 ] :?> IFSharpTypeDeclaration
75-
76-
77-
78- ModificationUtil.DeleteChildRange( sigDecl.EqualsToken.NextSibling, sigDecl.LastChild)
79- addNodesAfter sigDecl.EqualsToken [
80- Whitespace()
81- abbr.Copy()
82- ]
83- |> ignore
84- Some sigTypeGroup
85- | _ -> None
86- | :? ISimpleTypeRepresentation as repr ->
87- let sigTypeGroup = factory.CreateModuleMember( $" type {getName typeDecl} = int" )
88- match sigTypeGroup with
89- | :? ITypeDeclarationGroup as sigTypeGroup ->
90- let sigDecl = sigTypeGroup.TypeDeclarations.[ 0 ] :?> IFSharpTypeDeclaration
91- ModificationUtil.DeleteChildRange( sigDecl.EqualsToken.NextSibling, sigDecl.LastChild)
92- addNodesAfter sigDecl.EqualsToken [
93- NewLine( lineEnding)
94- Whitespace( indentation + moduleDecl.GetIndentSize())
95- repr.Copy()
96- for sigMember in sigMembers do
97- NewLine( lineEnding)
98- Whitespace( indentation + moduleDecl.GetIndentSize())
99- sigMember
100- ]
101- |> ignore
102- Some sigTypeGroup
103- | _ -> None
50+ | :? ITypeAbbreviationRepresentation
51+ | :? ISimpleTypeRepresentation -> Some typeDecl
10452 | _ -> None
105-
106-
107-
108- | _ -> None) // TODO: address this
109-
110- sigTypeDeclGroups.FirstOrDefault()
111- // TODO : ITypeExtensionDeclaration
53+ | _ -> None)
54+ |> Seq.mapi ( fun idx typeDecl ->
55+ let kw = if idx = 0 then " type" else " and"
56+ {| SignatureIdx = idx ; TypeDeclaration = typeDecl; SourceText = $" {kw} {getName typeDecl} = int" |})
57+ |> Seq.toArray
58+
59+ if Array.isEmpty supportedTypeDeclarations then null else
60+
61+ let sourceText = supportedTypeDeclarations |> Array.map ( fun info -> info.SourceText) |> String.concat " \n "
62+ let sigTypeDeclarationGroup = factory.CreateModuleMember( sourceText) :?> ITypeDeclarationGroup
63+
64+ if isNull sigTypeDeclarationGroup then null else
65+
66+ for info in supportedTypeDeclarations do
67+ let typeDecl : IFSharpTypeDeclaration = info.TypeDeclaration
68+ let sigTypeDecl = sigTypeDeclarationGroup.TypeDeclarations.[ info.SignatureIdx] :?> IFSharpTypeDeclaration
69+ if isNull sigTypeDecl then () else
70+
71+ let sigMembers =
72+ typeDecl.TypeMembers
73+ |> Seq.choose ( createMemberDeclaration >> Option.ofObj)
74+
75+ match typeDecl.TypeRepresentation with
76+ | :? ITypeAbbreviationRepresentation as abbr ->
77+ ModificationUtil.DeleteChildRange( sigTypeDecl.EqualsToken.NextSibling, sigTypeDecl.LastChild)
78+ addNodesAfter sigTypeDecl.EqualsToken [
79+ Whitespace()
80+ abbr.Copy()
81+ // TODO: there technically could be members here.
82+ // Although I think this would need the `with` keyword.
83+ ] |> ignore
84+ | :? ISimpleTypeRepresentation as repr ->
85+ ModificationUtil.DeleteChildRange( sigTypeDecl.EqualsToken.NextSibling, sigTypeDecl.LastChild)
86+ addNodesAfter sigTypeDecl.EqualsToken [
87+ NewLine( lineEnding)
88+ Whitespace( indentation + moduleDecl.GetIndentSize())
89+ repr.Copy()
90+ for sigMember in sigMembers do
91+ NewLine( lineEnding)
92+ Whitespace( indentation + moduleDecl.GetIndentSize())
93+ sigMember
94+ ] |> ignore
95+ | repr ->
96+ // This pattern match should match the types we filtered out earlier for supportedTypeDeclarations
97+ failwith $" Unexpected representation {repr.GetType()}"
98+
99+ sigTypeDeclarationGroup
112100
113101 | :? INestedModuleDeclaration as nestedNestedModule ->
114102 let nestedSigModule = factory.CreateNestedModule( nestedNestedModule.NameIdentifier.Name)
@@ -127,7 +115,7 @@ type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider)
127115 and processModuleLikeDeclaration ( indentation : int ) ( moduleDecl : IModuleLikeDeclaration ) ( moduleSig : IModuleLikeDeclaration ) : IFSharpTreeNode =
128116 for moduleMember in moduleDecl.Members do
129117 let signatureMember = createModuleMemberSig indentation moduleDecl moduleMember
130-
118+
131119 if isNotNull signatureMember then
132120 // newline + indentation whitespace
133121 addNodesAfter moduleSig.LastChild [
@@ -155,19 +143,18 @@ type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider)
155143 sb.Append( memberDecl.AccessModifier.GetText()) |> ignore
156144
157145 sb.Append( getName memberDecl) |> ignore
158- sb.Append( " : " ) |> ignore
159-
146+ sb.Append( " : " ) |> ignore
147+
160148 let symbolUse = memberDecl.GetFcsSymbolUse()
161149 if isNotNull symbolUse then
162150 let mfv = symbolUse.Symbol.As< FSharpMemberOrFunctionOrValue>()
163151 if isNotNull mfv then
164152 sb.Append( mfv.FullType.Format( symbolUse.DisplayContext)) |> ignore
165-
153+
166154 sb.ToString()
167155
168156 factory.CreateTypeMemberSignature( sourceString)
169157 | _ -> null
170-
171158
172159 for decl in fsharpFile.ModuleDeclarations do
173160 let signatureModule : IModuleLikeDeclaration =
@@ -182,13 +169,13 @@ type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider)
182169 | decl -> failwithf $" Unexpected declaration, got: %A {decl}"
183170
184171 ModificationUtil.AddChildAfter( signatureModule.LastChild, NewLine( lineEnding)) |> ignore
185- let signatureModule = processModuleLikeDeclaration 0 decl signatureModule
172+ let signatureModule = processModuleLikeDeclaration 0 decl signatureModule
186173 ModificationUtil.AddChild( signatureFile, signatureModule) |> ignore
187174
188175 signatureFile
189176
190177 override this.Text = " Generate signature file for current file"
191-
178+
192179 override this.IsAvailable _ =
193180 let solution = dataProvider.Solution
194181 let isSettingEnabled = solution.IsFSharpExperimentalFeatureEnabled( ExperimentalFeature.GenerateSignatureFile)
@@ -198,7 +185,7 @@ type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider)
198185 // TODO: don't check has pair in unit test
199186 let hasSignature = fcsService.FcsProjectProvider.HasPairFile dataProvider.SourceFile
200187 not hasSignature
201-
188+
202189 override this.ExecutePsiTransaction ( solution , _ ) =
203190 let projectFile = dataProvider.SourceFile.ToProjectFile()
204191 let fsharpFile = projectFile.GetPrimaryPsiFile() .AsFSharpFile()
@@ -211,7 +198,7 @@ type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider)
211198 let virtualPath = FileSystemPath.TryParse( fsiFile) .ToVirtualFileSystemPath()
212199 let relativeTo = RelativeTo( projectFile, RelativeToType.Before)
213200 let projectFile = transactionCookie.AddFile( projectFile.ParentFolder, virtualPath, context = OrderingContext( relativeTo))
214-
201+
215202 if ( not Shell.Instance.IsTestShell) then
216203 let navigationOptions = NavigationOptions.FromWindowContext( Shell.Instance.GetComponent< IMainWindowPopupWindowContext>() .Source, " " )
217204 NavigationManager
@@ -224,7 +211,7 @@ type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider)
224211 )
225212
226213 null
227-
214+
228215 // First test name would be: ``ModuleStructure 01`` , ``NamespaceStructure 01``
229-
230- // TODO: raise parser issue.
216+
217+ // TODO: raise parser issue.
0 commit comments