1
1
namespace JetBrains.ReSharper.Plugins.FSharp.Psi.Features.ContextActions
2
2
3
3
open System.IO
4
- open System.Linq
5
4
open System.Text
6
5
open FSharp.Compiler .Symbols
7
6
open JetBrains.Application .UI .PopupLayout
8
7
open JetBrains.ReSharper .Feature .Services .Navigation
9
- open JetBrains.ReSharper .Plugins .FSharp .Psi .Parsing
10
8
open JetBrains.ReSharper .Psi .Naming
11
9
open JetBrains.ReSharper .Psi .Tree
12
10
open JetBrains.DocumentManagers .Transactions .ProjectHostActions .Ordering
@@ -34,7 +32,7 @@ open JetBrains.ReSharper.Resources.Shell
34
32
type GenerateSignatureFileAction ( dataProvider : FSharpContextActionDataProvider ) =
35
33
inherit FSharpContextActionBase( dataProvider)
36
34
37
- let mkSignatureFile ( fsharpFile : IFSharpFile ) : IFSharpFile =
35
+ let mkSignatureFile ( fsharpFile : IFSharpFile ): IFSharpFile =
38
36
let factory : IFSharpElementFactory = fsharpFile.CreateElementFactory( extension = FSharpSignatureProjectFileType.FsiExtension)
39
37
let signatureFile : IFSharpFile = factory.CreateEmptyFile()
40
38
let lineEnding = fsharpFile.GetLineEnding()
@@ -43,72 +41,62 @@ type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider)
43
41
let rec createModuleMemberSig ( indentation : int ) ( moduleDecl : IModuleLikeDeclaration ) ( moduleMember : IModuleMember ) : IFSharpTreeNode =
44
42
match moduleMember with
45
43
| :? 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 =
49
46
typeGroup.TypeDeclarations
50
47
|> Seq.choose ( function
51
48
| :? 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
-
68
49
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
104
52
| _ -> 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
112
100
113
101
| :? INestedModuleDeclaration as nestedNestedModule ->
114
102
let nestedSigModule = factory.CreateNestedModule( nestedNestedModule.NameIdentifier.Name)
@@ -127,7 +115,7 @@ type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider)
127
115
and processModuleLikeDeclaration ( indentation : int ) ( moduleDecl : IModuleLikeDeclaration ) ( moduleSig : IModuleLikeDeclaration ) : IFSharpTreeNode =
128
116
for moduleMember in moduleDecl.Members do
129
117
let signatureMember = createModuleMemberSig indentation moduleDecl moduleMember
130
-
118
+
131
119
if isNotNull signatureMember then
132
120
// newline + indentation whitespace
133
121
addNodesAfter moduleSig.LastChild [
@@ -155,19 +143,18 @@ type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider)
155
143
sb.Append( memberDecl.AccessModifier.GetText()) |> ignore
156
144
157
145
sb.Append( getName memberDecl) |> ignore
158
- sb.Append( " : " ) |> ignore
159
-
146
+ sb.Append( " : " ) |> ignore
147
+
160
148
let symbolUse = memberDecl.GetFcsSymbolUse()
161
149
if isNotNull symbolUse then
162
150
let mfv = symbolUse.Symbol.As< FSharpMemberOrFunctionOrValue>()
163
151
if isNotNull mfv then
164
152
sb.Append( mfv.FullType.Format( symbolUse.DisplayContext)) |> ignore
165
-
153
+
166
154
sb.ToString()
167
155
168
156
factory.CreateTypeMemberSignature( sourceString)
169
157
| _ -> null
170
-
171
158
172
159
for decl in fsharpFile.ModuleDeclarations do
173
160
let signatureModule : IModuleLikeDeclaration =
@@ -182,13 +169,13 @@ type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider)
182
169
| decl -> failwithf $" Unexpected declaration, got: %A {decl}"
183
170
184
171
ModificationUtil.AddChildAfter( signatureModule.LastChild, NewLine( lineEnding)) |> ignore
185
- let signatureModule = processModuleLikeDeclaration 0 decl signatureModule
172
+ let signatureModule = processModuleLikeDeclaration 0 decl signatureModule
186
173
ModificationUtil.AddChild( signatureFile, signatureModule) |> ignore
187
174
188
175
signatureFile
189
176
190
177
override this.Text = " Generate signature file for current file"
191
-
178
+
192
179
override this.IsAvailable _ =
193
180
let solution = dataProvider.Solution
194
181
let isSettingEnabled = solution.IsFSharpExperimentalFeatureEnabled( ExperimentalFeature.GenerateSignatureFile)
@@ -198,7 +185,7 @@ type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider)
198
185
// TODO: don't check has pair in unit test
199
186
let hasSignature = fcsService.FcsProjectProvider.HasPairFile dataProvider.SourceFile
200
187
not hasSignature
201
-
188
+
202
189
override this.ExecutePsiTransaction ( solution , _ ) =
203
190
let projectFile = dataProvider.SourceFile.ToProjectFile()
204
191
let fsharpFile = projectFile.GetPrimaryPsiFile() .AsFSharpFile()
@@ -211,7 +198,7 @@ type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider)
211
198
let virtualPath = FileSystemPath.TryParse( fsiFile) .ToVirtualFileSystemPath()
212
199
let relativeTo = RelativeTo( projectFile, RelativeToType.Before)
213
200
let projectFile = transactionCookie.AddFile( projectFile.ParentFolder, virtualPath, context = OrderingContext( relativeTo))
214
-
201
+
215
202
if ( not Shell.Instance.IsTestShell) then
216
203
let navigationOptions = NavigationOptions.FromWindowContext( Shell.Instance.GetComponent< IMainWindowPopupWindowContext>() .Source, " " )
217
204
NavigationManager
@@ -224,7 +211,7 @@ type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider)
224
211
)
225
212
226
213
null
227
-
214
+
228
215
// First test name would be: ``ModuleStructure 01`` , ``NamespaceStructure 01``
229
-
230
- // TODO: raise parser issue.
216
+
217
+ // TODO: raise parser issue.
0 commit comments