Skip to content

Commit ccaef3e

Browse files
committed
Generating LspServer interface
1 parent 38beb5e commit ccaef3e

File tree

4 files changed

+269
-8
lines changed

4 files changed

+269
-8
lines changed

src/ClientServer.cg.fs

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
namespace Ionide.LanguageServerProtocol
2+
3+
open Ionide.LanguageServerProtocol.Types
4+
5+
type ILSPServer =
6+
// Notifications
7+
abstract member WorkspaceDidChangeWorkspaceFolders: DidChangeWorkspaceFoldersParams -> Async<unit>
8+
abstract member WindowWorkDoneProgressCancel: WorkDoneProgressCancelParams -> Async<unit>
9+
abstract member WorkspaceDidCreateFiles: CreateFilesParams -> Async<unit>
10+
abstract member WorkspaceDidRenameFiles: RenameFilesParams -> Async<unit>
11+
abstract member WorkspaceDidDeleteFiles: DeleteFilesParams -> Async<unit>
12+
abstract member NotebookDocumentDidOpen: DidOpenNotebookDocumentParams -> Async<unit>
13+
abstract member NotebookDocumentDidChange: DidChangeNotebookDocumentParams -> Async<unit>
14+
abstract member NotebookDocumentDidSave: DidSaveNotebookDocumentParams -> Async<unit>
15+
abstract member NotebookDocumentDidClose: DidCloseNotebookDocumentParams -> Async<unit>
16+
abstract member Initialized: InitializedParams -> Async<unit>
17+
abstract member Exit: unit -> Async<unit>
18+
abstract member WorkspaceDidChangeConfiguration: DidChangeConfigurationParams -> Async<unit>
19+
abstract member TextDocumentDidOpen: DidOpenTextDocumentParams -> Async<unit>
20+
abstract member TextDocumentDidChange: DidChangeTextDocumentParams -> Async<unit>
21+
abstract member TextDocumentDidClose: DidCloseTextDocumentParams -> Async<unit>
22+
abstract member TextDocumentDidSave: DidSaveTextDocumentParams -> Async<unit>
23+
abstract member TextDocumentWillSave: WillSaveTextDocumentParams -> Async<unit>
24+
abstract member WorkspaceDidChangeWatchedFiles: DidChangeWatchedFilesParams -> Async<unit>
25+
abstract member SetTrace: SetTraceParams -> Async<unit>
26+
abstract member CancelRequest: CancelParams -> Async<unit>
27+
abstract member Progress: ProgressParams -> Async<unit>
28+
// Requests
29+
abstract member TextDocumentImplementation: ImplementationParams -> Option<U2<Definition,DefinitionLink array>>
30+
abstract member TextDocumentTypeDefinition: TypeDefinitionParams -> Option<U2<Definition,DefinitionLink array>>
31+
abstract member TextDocumentDocumentColor: DocumentColorParams -> ColorInformation array
32+
abstract member TextDocumentColorPresentation: ColorPresentationParams -> ColorPresentation array
33+
abstract member TextDocumentFoldingRange: FoldingRangeParams -> Option<FoldingRange array>
34+
abstract member TextDocumentDeclaration: DeclarationParams -> Option<U2<Declaration,DeclarationLink array>>
35+
abstract member TextDocumentSelectionRange: SelectionRangeParams -> Option<SelectionRange array>
36+
abstract member TextDocumentPrepareCallHierarchy: CallHierarchyPrepareParams -> Option<CallHierarchyItem array>
37+
38+
abstract member CallHierarchyIncomingCalls:
39+
CallHierarchyIncomingCallsParams -> Option<CallHierarchyIncomingCall array>
40+
41+
abstract member CallHierarchyOutgoingCalls:
42+
CallHierarchyOutgoingCallsParams -> Option<CallHierarchyOutgoingCall array>
43+
44+
abstract member TextDocumentSemanticTokensFull: SemanticTokensParams -> Option<SemanticTokens>
45+
46+
abstract member TextDocumentSemanticTokensFullDelta:
47+
SemanticTokensDeltaParams -> Option<U2<SemanticTokens,SemanticTokensDelta>>
48+
49+
abstract member TextDocumentSemanticTokensRange: SemanticTokensRangeParams -> Option<SemanticTokens>
50+
abstract member TextDocumentLinkedEditingRange: LinkedEditingRangeParams -> Option<LinkedEditingRanges>
51+
abstract member WorkspaceWillCreateFiles: CreateFilesParams -> Option<WorkspaceEdit>
52+
abstract member WorkspaceWillRenameFiles: RenameFilesParams -> Option<WorkspaceEdit>
53+
abstract member WorkspaceWillDeleteFiles: DeleteFilesParams -> Option<WorkspaceEdit>
54+
abstract member TextDocumentMoniker: MonikerParams -> Option<Moniker array>
55+
abstract member TextDocumentPrepareTypeHierarchy: TypeHierarchyPrepareParams -> Option<TypeHierarchyItem array>
56+
abstract member TypeHierarchySupertypes: TypeHierarchySupertypesParams -> Option<TypeHierarchyItem array>
57+
abstract member TypeHierarchySubtypes: TypeHierarchySubtypesParams -> Option<TypeHierarchyItem array>
58+
abstract member TextDocumentInlineValue: InlineValueParams -> Option<InlineValue array>
59+
abstract member TextDocumentInlayHint: InlayHintParams -> Option<InlayHint array>
60+
abstract member InlayHintResolve: InlayHint -> InlayHint
61+
abstract member TextDocumentDiagnostic: DocumentDiagnosticParams -> DocumentDiagnosticReport
62+
abstract member WorkspaceDiagnostic: WorkspaceDiagnosticParams -> WorkspaceDiagnosticReport
63+
abstract member Initialize: InitializeParams -> InitializeResult
64+
abstract member Shutdown: unit -> unit
65+
abstract member TextDocumentWillSaveWaitUntil: WillSaveTextDocumentParams -> Option<TextEdit array>
66+
abstract member TextDocumentCompletion: CompletionParams -> Option<U2<CompletionItem array,CompletionList>>
67+
abstract member CompletionItemResolve: CompletionItem -> CompletionItem
68+
abstract member TextDocumentHover: HoverParams -> Option<Hover>
69+
abstract member TextDocumentSignatureHelp: SignatureHelpParams -> Option<SignatureHelp>
70+
abstract member TextDocumentDefinition: DefinitionParams -> Option<U2<Definition,DefinitionLink array>>
71+
abstract member TextDocumentReferences: ReferenceParams -> Option<Location array>
72+
abstract member TextDocumentDocumentHighlight: DocumentHighlightParams -> Option<DocumentHighlight array>
73+
74+
abstract member TextDocumentDocumentSymbol:
75+
DocumentSymbolParams -> Option<U2<SymbolInformation array,DocumentSymbol array>>
76+
77+
abstract member TextDocumentCodeAction: CodeActionParams -> Option<U2<Command,CodeAction> array>
78+
abstract member CodeActionResolve: CodeAction -> CodeAction
79+
abstract member WorkspaceSymbol: WorkspaceSymbolParams -> Option<U2<SymbolInformation array,WorkspaceSymbol array>>
80+
abstract member WorkspaceSymbolResolve: WorkspaceSymbol -> WorkspaceSymbol
81+
abstract member TextDocumentCodeLens: CodeLensParams -> Option<CodeLens array>
82+
abstract member CodeLensResolve: CodeLens -> CodeLens
83+
abstract member TextDocumentDocumentLink: DocumentLinkParams -> Option<DocumentLink array>
84+
abstract member DocumentLinkResolve: DocumentLink -> DocumentLink
85+
abstract member TextDocumentFormatting: DocumentFormattingParams -> Option<TextEdit array>
86+
abstract member TextDocumentRangeFormatting: DocumentRangeFormattingParams -> Option<TextEdit array>
87+
abstract member TextDocumentOnTypeFormatting: DocumentOnTypeFormattingParams -> Option<TextEdit array>
88+
abstract member TextDocumentRename: RenameParams -> Option<WorkspaceEdit>
89+
abstract member TextDocumentPrepareRename: PrepareRenameParams -> Option<PrepareRenameResult>
90+
abstract member WorkspaceExecuteCommand: ExecuteCommandParams -> Option<LSPAny>

src/Ionide.LanguageServerProtocol.fsproj

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
<Compile Include="Types.fs" />
2525
<Compile Include="Types.cg.fs" />
2626
<Compile Include="TypeDefaults.fs" />
27+
<Compile Include="ClientServer.cg.fs" />
2728
<Compile Include="Client.fs" />
2829
<Compile Include="Server.fs" />
2930
<Compile Include="OptionConverter.fs" />
@@ -43,14 +44,15 @@
4344
<ItemGroup>
4445
<_MetaModelInputs Include="$(MSBuildThisFileDirectory)../data/$(LSPVersion)/metaModel.json" />
4546
<_MetaModelOutputs Include="$(MSBuildThisFileDirectory)Types.cg.fs" />
47+
<_MetaModelClientServerOutputs Include="$(MSBuildThisFileDirectory)ClientServer.cg.fs" />
4648
</ItemGroup>
4749

4850
<Target Name="EnsureRegeneration" Condition="'$(ForceRegenerate)' == 'true'">
4951
<Delete Files="@(_MetaModelOutputs)" />
5052
</Target>
5153

5254
<Target Name="RegenerateTypes" Inputs="@(_MetaModelInputs)" DependsOnTargets="EnsureRegeneration"
53-
Outputs="@(_MetaModelOutputs)"
55+
Outputs="@(_MetaModelOutputs); @(_MetaModelClientServerOutputs)"
5456
BeforeTargets="PrepareForBuild">
5557
<ItemGroup>
5658
<_GeneratorProject Include="../tools/MetaModelGenerator/MetaModelGenerator.fsproj" />
@@ -70,5 +72,18 @@
7072

7173
<Exec
7274
Command="@(_GenerateCommand, ' ')" />
75+
76+
<ItemGroup>
77+
<_GenerateCommand2 Include="dotnet;@(_GeneratorApp)" />
78+
<_GenerateCommand2 Include="clientserver" />
79+
<_GenerateCommand2 Include="--metamodelpath" />
80+
<_GenerateCommand2 Include="%(_MetaModelInputs.FullPath)" />
81+
<_GenerateCommand2 Include="--outputfilepath" />
82+
<_GenerateCommand2 Include="%(_MetaModelClientServerOutputs.FullPath)" />
83+
</ItemGroup>
84+
85+
<Exec
86+
Command="@(_GenerateCommand2, ' ')" />
87+
7388
</Target>
7489
</Project>

tools/MetaModelGenerator/GenerateTypes.fs

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -981,4 +981,160 @@ See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17
981981
formattedText
982982
|> writeToFile outputPath
983983
|> Async.AwaitTask
984+
}
985+
986+
987+
let generateClientServer (parsedMetaModel : MetaModel.MetaModel) outputPath =
988+
async {
989+
printfn "Writing to %s" outputPath
990+
let writeToFile path contents = File.WriteAllTextAsync(path, contents)
991+
992+
993+
let requests =
994+
parsedMetaModel.Requests
995+
|> Array.filter Proposed.checkProposed
996+
|> Array.groupBy(fun x ->x.MessageDirection)
997+
|> Map
998+
let notifications =
999+
parsedMetaModel.Notifications
1000+
|> Array.filter Proposed.checkProposed
1001+
|> Array.groupBy(fun x -> x.MessageDirection)
1002+
|> Map
1003+
1004+
1005+
let serverRequests = [
1006+
yield! requests |> Map.tryFind MetaModel.MessageDirection.ClientToServer |> Option.defaultValue [||]
1007+
yield! requests |> Map.tryFind MetaModel.MessageDirection.Both |> Option.defaultValue [||]
1008+
]
1009+
1010+
let serverNotifications = [
1011+
yield! notifications |> Map.tryFind MetaModel.MessageDirection.ClientToServer |> Option.defaultValue [||]
1012+
yield! notifications |> Map.tryFind MetaModel.MessageDirection.Both |> Option.defaultValue [||]
1013+
]
1014+
1015+
1016+
let normalizeMethod (s : string) =
1017+
let parts = s.Split("/", StringSplitOptions.RemoveEmptyEntries ||| StringSplitOptions.TrimEntries)
1018+
parts
1019+
|> Array.filter (fun x -> x <> "$")
1020+
|> Array.map (fun x -> (string x.[0]).ToUpper() + x.[1..]) |> String.concat ""
1021+
1022+
let oak =
1023+
Ast.Oak () {
1024+
Namespace("Ionide.LanguageServerProtocol") {
1025+
Open("Ionide.LanguageServerProtocol.Types")
1026+
TypeDefn("ILSPServer") {
1027+
let notificationComment =
1028+
SyntaxOak.TriviaNode(SyntaxOak.CommentOnSingleLine("// Notifications"), Fantomas.FCS.Text.Range.Zero)
1029+
1030+
let mutable writtenNotificationComment = false
1031+
1032+
for n in serverNotifications do
1033+
let methodName = normalizeMethod n.Method
1034+
let parameters = [
1035+
match n.Params with
1036+
| None -> yield (None, "unit")
1037+
| Some ps ->
1038+
for p in ps do
1039+
match p with
1040+
| MetaModel.Type.ReferenceType r -> yield (None, r.Name)
1041+
| _ -> ()
1042+
]
1043+
let returnType = "Async<unit>"
1044+
1045+
1046+
1047+
let wb = AbstractSlot(methodName, parameters, returnType)
1048+
1049+
let widget = wb |> Gen.mkOak
1050+
if not writtenNotificationComment then
1051+
widget.AddBefore(notificationComment)
1052+
writtenNotificationComment <- true
1053+
1054+
EscapeHatch(widget)
1055+
let requestComment =
1056+
SyntaxOak.TriviaNode(SyntaxOak.CommentOnSingleLine("// Requests"), Fantomas.FCS.Text.Range.Zero)
1057+
1058+
let mutable writtenRequestComment = false
1059+
1060+
1061+
for r in serverRequests do
1062+
let methodName = normalizeMethod r.Method
1063+
let parameters = [
1064+
match r.Params with
1065+
| None -> yield (None, "unit")
1066+
| Some ps ->
1067+
for p in ps do
1068+
match p with
1069+
| MetaModel.Type.ReferenceType r -> yield (None, r.Name)
1070+
| _ -> ()
1071+
]
1072+
let returnType =
1073+
let rec returnType (ty: MetaModel.Type) =
1074+
// TODO: Don't use strings
1075+
match ty with
1076+
| MetaModel.Type.ReferenceType r -> r.Name
1077+
| MetaModel.Type.BaseType b ->
1078+
match b.Name with
1079+
| MetaModel.BaseTypes.Null -> "unit"
1080+
| MetaModel.BaseTypes.Boolean -> "bool"
1081+
| MetaModel.BaseTypes.Integer -> "int"
1082+
| MetaModel.BaseTypes.Decimal -> "float"
1083+
| MetaModel.BaseTypes.String -> "string"
1084+
| _ -> "JToken"
1085+
| MetaModel.Type.OrType o ->
1086+
// TS types can have optional properties (myKey?: string)
1087+
// and unions with null (string | null)
1088+
// we need to handle both cases
1089+
let isOptional, items =
1090+
if Array.exists isNullableType o.Items then
1091+
true,
1092+
o.Items
1093+
|> Array.filter (fun x -> not (isNullableType x))
1094+
else
1095+
false, o.Items
1096+
1097+
let types = items |> Array.map returnType
1098+
let retType =
1099+
if types.Length > 1 then
1100+
let duType = $"U{types.Length}"
1101+
let inner = String.Join(",", types)
1102+
$"{duType}<{inner}>"
1103+
else
1104+
types.[0]
1105+
if isOptional then
1106+
$"Option<{retType}>"
1107+
else
1108+
retType
1109+
| MetaModel.Type.ArrayType a ->
1110+
$"{returnType a.Element} array"
1111+
| _ -> "Async<unit>"
1112+
1113+
returnType r.Result
1114+
1115+
1116+
let wb = AbstractSlot(methodName, parameters, returnType)
1117+
1118+
let widget = wb |> Gen.mkOak
1119+
if not writtenRequestComment then
1120+
widget.AddBefore(requestComment)
1121+
writtenRequestComment <- true
1122+
1123+
EscapeHatch(widget)
1124+
1125+
}
1126+
}
1127+
}
1128+
1129+
1130+
let! formattedText =
1131+
oak
1132+
|> Gen.mkOak
1133+
|> CodeFormatter.FormatOakAsync
1134+
1135+
do!
1136+
formattedText
1137+
|> writeToFile outputPath
1138+
|> Async.AwaitTask
1139+
9841140
}

tools/MetaModelGenerator/Program.fs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,12 @@ module Main =
2626

2727
type CommandArgs =
2828
| [<CliPrefix(CliPrefix.None)>] Types of ParseResults<TypeArgs>
29-
// | [<CliPrefix(CliPrefix.None)>] ClientServer of ParseResults<ClientServerArgs>
29+
| [<CliPrefix(CliPrefix.None)>] ClientServer of ParseResults<ClientServerArgs>
3030
interface IArgParserTemplate with
3131
member this.Usage =
3232
match this with
3333
| Types _ -> "Generates Types from metaModel.json."
34-
// | ClientServer _ -> "Generates Client/Server"
34+
| ClientServer _ -> "Generates Client/Server"
3535
let readMetaModel metamodelPath = async {
3636

3737
printfn "Reading in %s" metamodelPath
@@ -63,12 +63,12 @@ module Main =
6363
let metaModel = readMetaModel metaModelPath |> Async.RunSynchronously
6464
GenerateTypes.generateType metaModel OutputFilePath |> Async.RunSynchronously
6565

66-
// | ClientServer r ->
67-
68-
// let metaModelPath = r.GetResult <@ ClientServerArgs.MetaModelPath @>
69-
// let OutputFilePath = r.GetResult <@ ClientServerArgs.OutputFilePath @>
70-
// let metaModel = readMetaModel metaModelPath |> Async.RunSynchronously
66+
| ClientServer r ->
7167

68+
let metaModelPath = r.GetResult <@ ClientServerArgs.MetaModelPath @>
69+
let OutputFilePath = r.GetResult <@ ClientServerArgs.OutputFilePath @>
70+
let metaModel = readMetaModel metaModelPath |> Async.RunSynchronously
71+
GenerateTypes.generateClientServer metaModel OutputFilePath |> Async.RunSynchronously
7272
// let requests =
7373
// metaModel.Requests
7474
// |> Array.groupBy(fun x ->x.MessageDirection)

0 commit comments

Comments
 (0)