1
1
namespace JetBrains.ReSharper.Plugins.FSharp.Psi.Features.ContextActions
2
2
3
3
open System.IO
4
+ open JetBrains.ReSharper .Psi .Tree
5
+ open JetBrains.DocumentManagers .Transactions .ProjectHostActions .Ordering
6
+ open JetBrains.ProjectModel .ProjectsHost
7
+ open JetBrains.RdBackend .Common .Features .ProjectModel
4
8
open JetBrains.ReSharper .Feature .Services .ContextActions
5
9
open JetBrains.ReSharper .Plugins .FSharp .Psi
6
10
open JetBrains.ReSharper .Plugins .FSharp .Psi .Features .Intentions
7
- open type JetBrains.ReSharper .Psi .PsiSourceFileExtensions
8
11
open JetBrains.ReSharper .Plugins .FSharp
12
+ open JetBrains.ReSharper .Plugins .FSharp .Psi .Impl .Tree
9
13
open JetBrains.ReSharper .Plugins .FSharp .Psi .Tree
10
14
open JetBrains.ReSharper .Psi
11
15
open JetBrains.ReSharper .Psi .ExtensionsAPI .Tree
12
16
13
- type TopLevelModuleOrNamespace =
14
- {
15
- IsModule: bool
16
- Name: string
17
- NestedModules: NestedModule list
18
- }
19
-
20
- and NestedModule =
21
- {
22
- Name: string
23
- NestedModules: NestedModule list
24
- }
17
+ // extract value -> ctrl alt v
18
+ // undo that -> ctrl alt n
25
19
26
20
[<ContextAction( Group = " F#" , Name = " Generate signature file for current file" , Priority = 1 s,
27
21
Description = " Generate signature file for current file." ) >]
28
22
type GenerateSignatureFileAction ( dataProvider : FSharpContextActionDataProvider ) =
29
23
inherit FSharpContextActionBase( dataProvider)
30
-
24
+
31
25
let mkSignatureFile ( fsharpFile : IFSharpFile ) : IFSharpFile =
32
26
let factory : IFSharpElementFactory = fsharpFile.CreateElementFactory()
33
27
let signatureFile : IFSharpFile = factory.CreateEmptyFile()
34
-
35
- let rec processModuleMembers ( parent : IFSharpTreeNode ) ( members : IModuleMember seq ) =
36
- for m in members do
37
- match m with
38
- | :? INestedModuleDeclaration as nmd ->
39
- let nestedModuleNode = factory.CreateNestedModule( nmd.NameIdentifier.Name)
40
- // TODO: if the nested module has nested modules, clear the content (`begin end`) and process them.
41
- ModificationUtil.AddChild( parent, nestedModuleNode) |> ignore
42
- | _ -> ()
28
+ let lineEnding = fsharpFile.GetLineEnding()
29
+
30
+ let rec processModuleLikeDeclaration ( indentation : int ) ( moduleDecl : IModuleLikeDeclaration ) ( moduleSig : IModuleLikeDeclaration ) : IFSharpTreeNode =
31
+ for moduleMember in moduleDecl.Members do
32
+ // newline + indentation whitespace
33
+ addNodesAfter moduleSig.LastChild [
34
+ NewLine( lineEnding)
35
+ Whitespace( indentation)
36
+ match moduleMember with
37
+ | :? INestedModuleDeclaration as nestedNestedModule ->
38
+ let nestedSigModule = factory.CreateNestedModule( nestedNestedModule.NameIdentifier.Name)
39
+ let members = nestedNestedModule.Members
40
+ let shouldEmptyContent =
41
+ not members.IsEmpty
42
+ && members |> Seq.forall ( function | :? IExpressionStatement -> false | _ -> true )
43
+
44
+ if shouldEmptyContent then
45
+ ModificationUtil.DeleteChildRange ( nestedSigModule.EqualsToken.NextSibling, nestedSigModule.LastChild)
46
+ processModuleLikeDeclaration ( indentation + moduleDecl.GetIndentSize()) nestedNestedModule nestedSigModule
47
+ | :? IOpenStatement as openStatement ->
48
+ openStatement.Copy()
49
+ | _ -> ()
50
+ ]
51
+ |> ignore
52
+
53
+ moduleSig
43
54
44
55
for decl in fsharpFile.ModuleDeclarations do
45
- match decl with
46
- | :? INamedModuleDeclaration as nmd ->
47
- let moduleNode = factory.CreateModule( nmd.NameIdentifier.Name)
48
- processModuleMembers moduleNode nmd.Members
49
- ModificationUtil.AddChild( signatureFile, moduleNode) |> ignore
50
- | :? INamedNamespaceDeclaration as nnd ->
51
- let namespaceNode = factory.CreateModule( nnd.NameIdentifier.Name)
52
- processModuleMembers namespaceNode nnd.Members
53
- ModificationUtil.AddChild( signatureFile, namespaceNode) |> ignore
54
- | _ -> ()
56
+ let signatureModule : IModuleLikeDeclaration =
57
+ match decl with
58
+ | :? INamedModuleDeclaration as nmd ->
59
+ factory.CreateModule( nmd.DeclaredElement.GetClrName() .FullName)
60
+ | :? IGlobalNamespaceDeclaration ->
61
+ factory.CreateNamespace( " global" ) :?> _
62
+ | :? INamedNamespaceDeclaration as nnd ->
63
+ // TODO: add an interface that could unify named and global namespace.
64
+ factory.CreateNamespace( nnd.QualifiedName) :?> _
65
+ | decl -> failwithf $" Unexpected declaration, got: %A {decl}"
66
+
67
+ ModificationUtil.AddChildAfter( signatureModule.LastChild, NewLine( lineEnding)) |> ignore
68
+ let signatureModule = processModuleLikeDeclaration 0 decl signatureModule
69
+ ModificationUtil.AddChild( signatureFile, signatureModule) |> ignore
55
70
56
71
signatureFile
57
72
@@ -71,30 +86,18 @@ type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider)
71
86
let fsharpFile = projectFile.GetPrimaryPsiFile() .AsFSharpFile()
72
87
let physicalPath = dataProvider.SourceFile.ToProjectFile() .Location.FileAccessPath
73
88
let fsiFile = Path.ChangeExtension( physicalPath, " .fsi" )
74
-
75
89
let signatureFile = mkSignatureFile fsharpFile
76
- // try
77
- // let currentFSharpFile = dataProvider.PsiFile
78
- // let fcsService = currentFSharpFile.FcsCheckerService
79
- // let checkResult = fcsService.ParseAndCheckFile(currentFSharpFile.GetSourceFile(), "for signature file", true)
80
- // do
81
- // match checkResult with
82
- // | None -> ()
83
- // | Some { CheckResults = checkResult } ->
84
- //
85
- // match checkResult.GenerateSignature() with
86
- // | None -> ()
87
- // | Some signatureSourceText ->
88
- // let content = string signatureSourceText
89
- // File.WriteAllText(fsiFile, content)
90
- // with ex ->
91
- // // TODO: show some balloon thing?
92
- // ()
90
+ File.WriteAllText( fsiFile, signatureFile.GetText())
93
91
94
- // solution.InvokeUnderTransaction(fun transactionCookie ->
95
- // let virtualPath = FileSystemPath.TryParse(fsiFile).ToVirtualFileSystemPath()
96
- // let relativeTo = RelativeTo(projectFile, RelativeToType.Before)
97
- // transactionCookie.AddFile(projectFile.ParentFolder, virtualPath, context = OrderingContext(relativeTo))
98
- // |> ignore)
92
+ solution.InvokeUnderTransaction( fun transactionCookie ->
93
+ let virtualPath = FileSystemPath.TryParse( fsiFile) .ToVirtualFileSystemPath()
94
+ let relativeTo = RelativeTo( projectFile, RelativeToType.Before)
95
+ transactionCookie.AddFile( projectFile.ParentFolder, virtualPath, context = OrderingContext( relativeTo))
96
+ |> ignore)
99
97
100
- null
98
+ // TODO: it would be nice if we opened the signature file that was just created. Maybe split?
99
+ null
100
+
101
+ // First test name would be: ``ModuleStructure 01`` , ``NamespaceStructure 01``
102
+
103
+ // TODO: raise parser issue.
0 commit comments