mirror of
https://github.com/golang/go
synced 2024-11-18 12:54:44 -07:00
internal/lsp: upgrade to current version of LSP
There are a number of new RPCs, for CallHeirarchy, SemanticTokens, and WorkDoneProgress. Some of the messages now have two slashes, like 'textDocument/semanticTokens/edits'. A few unused RegistrationOptions are no longer present. Only generated code has changed. There are no changes any other .go code. The typescript code needed a new heuristic for finding the RPCs Change-Id: Ie6942abac3a0cd60e86afe3fdbc6f6b0e9b30cb0 Reviewed-on: https://go-review.googlesource.com/c/tools/+/216537 Run-TryBot: Peter Weinberger <pjw@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Rebecca Stambler <rstambler@golang.org>
This commit is contained in:
parent
d33eef8e68
commit
91d59a9776
@ -2,8 +2,8 @@ package protocol
|
||||
|
||||
// Package protocol contains data types and code for LSP jsonrpcs
|
||||
// generated automatically from vscode-languageserver-node
|
||||
// commit: 635ab1fe6f8c57ce9402e573d007f24d6d290fd3
|
||||
// last fetched Fri Jan 10 2020 17:17:33 GMT-0500 (Eastern Standard Time)
|
||||
// commit: 7b90c29d0cb5cd7b9c41084f6cb3781a955adeba
|
||||
// last fetched Thu Jan 23 2020 11:10:31 GMT-0500 (Eastern Standard Time)
|
||||
|
||||
// Code generated (see typescript/README.md) DO NOT EDIT.
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Package protocol contains data types and code for LSP jsonrpcs
|
||||
// generated automatically from vscode-languageserver-node
|
||||
// commit: 635ab1fe6f8c57ce9402e573d007f24d6d290fd3
|
||||
// last fetched Fri Jan 10 2020 17:17:33 GMT-0500 (Eastern Standard Time)
|
||||
// commit: 7b90c29d0cb5cd7b9c41084f6cb3781a955adeba
|
||||
// last fetched Thu Jan 23 2020 11:10:31 GMT-0500 (Eastern Standard Time)
|
||||
package protocol
|
||||
|
||||
// Code generated (see typescript/README.md) DO NOT EDIT.
|
||||
@ -44,6 +44,111 @@ type ApplyWorkspaceEditResponse struct {
|
||||
FailedChange float64 `json:"failedChange,omitempty"`
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an incoming call, e.g. a caller of a method or constructor.
|
||||
*
|
||||
* @since 3.16.0 - Proposed state
|
||||
*/
|
||||
type CallHierarchyIncomingCall struct {
|
||||
/**
|
||||
* The item that makes the call.
|
||||
*/
|
||||
From CallHierarchyItem `json:"from"`
|
||||
/**
|
||||
* The range at which at which the calls appears. This is relative to the caller
|
||||
* denoted by [`this.from`](#CallHierarchyIncomingCall.from).
|
||||
*/
|
||||
FromRanges []Range `json:"fromRanges"`
|
||||
}
|
||||
|
||||
/**
|
||||
* The parameter of a `callHierarchy/incomingCalls` request.
|
||||
*
|
||||
* @since 3.16.0 - Proposed state
|
||||
*/
|
||||
type CallHierarchyIncomingCallsParams struct {
|
||||
Item CallHierarchyItem `json:"item"`
|
||||
WorkDoneProgressParams
|
||||
PartialResultParams
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents programming constructs like functions or constructors in the context
|
||||
* of call hierarchy.
|
||||
*
|
||||
* @since 3.16.0 - Proposed state
|
||||
*/
|
||||
type CallHierarchyItem struct {
|
||||
/**
|
||||
* The name of this item.
|
||||
*/
|
||||
Name string `json:"name"`
|
||||
/**
|
||||
* The kind of this item.
|
||||
*/
|
||||
Kind SymbolKind `json:"kind"`
|
||||
/**
|
||||
* Tags for this item.
|
||||
*/
|
||||
Tags []SymbolTag `json:"tags,omitempty"`
|
||||
/**
|
||||
* More detail for this item, e.g. the signature of a function.
|
||||
*/
|
||||
Detail string `json:"detail,omitempty"`
|
||||
/**
|
||||
* The resource identifier of this item.
|
||||
*/
|
||||
URI DocumentURI `json:"uri"`
|
||||
/**
|
||||
* The range enclosing this symbol not including leading/trailing whitespace but everything else, e.g. comments and code.
|
||||
*/
|
||||
Range Range `json:"range"`
|
||||
/**
|
||||
* The range that should be selected and revealed when this symbol is being picked, e.g. the name of a function.
|
||||
* Must be contained by the [`range`](#CallHierarchyItem.range).
|
||||
*/
|
||||
SelectionRange Range `json:"selectionRange"`
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an outgoing call, e.g. calling a getter from a method or a method from a constructor etc.
|
||||
*
|
||||
* @since 3.16.0 - Proposed state
|
||||
*/
|
||||
type CallHierarchyOutgoingCall struct {
|
||||
/**
|
||||
* The item that is called.
|
||||
*/
|
||||
To CallHierarchyItem `json:"to"`
|
||||
/**
|
||||
* The range at which this item is called. This is the range relative to the caller, e.g the item
|
||||
* passed to [`provideCallHierarchyOutgoingCalls`](#CallHierarchyItemProvider.provideCallHierarchyOutgoingCalls)
|
||||
* and not [`this.to`](#CallHierarchyOutgoingCall.to).
|
||||
*/
|
||||
FromRanges []Range `json:"fromRanges"`
|
||||
}
|
||||
|
||||
/**
|
||||
* The parameter of a `callHierarchy/outgoingCalls` request.
|
||||
*
|
||||
* @since 3.16.0 - Proposed state
|
||||
*/
|
||||
type CallHierarchyOutgoingCallsParams struct {
|
||||
Item CallHierarchyItem `json:"item"`
|
||||
WorkDoneProgressParams
|
||||
PartialResultParams
|
||||
}
|
||||
|
||||
/**
|
||||
* The parameter of a `textDocument/prepareCallHierarchy` request.
|
||||
*
|
||||
* @since 3.16.0 - Proposed state
|
||||
*/
|
||||
type CallHierarchyPrepareParams struct {
|
||||
TextDocumentPositionParams
|
||||
WorkDoneProgressParams
|
||||
}
|
||||
|
||||
type CancelParams struct {
|
||||
/**
|
||||
* The request id to cancel.
|
||||
@ -70,20 +175,23 @@ type ClientCapabilities = struct {
|
||||
* Text document specific client capabilities.
|
||||
*/
|
||||
TextDocument TextDocumentClientCapabilities `json:"textDocument,omitempty"`
|
||||
/**
|
||||
* Window specific client capabilities.
|
||||
*/
|
||||
Window interface{} `json:"window,omitempty"`
|
||||
Window struct {
|
||||
/**
|
||||
* Window specific client capabilities.
|
||||
*/
|
||||
Window interface{} `json:"window,omitempty"`
|
||||
/**
|
||||
* Whether client supports handling progress notifications. If set servers are allowed to
|
||||
* report in `workDoneProgress` property in the request specific server capabilities.
|
||||
*
|
||||
* Since 3.15.0
|
||||
*/
|
||||
WorkDoneProgress bool `json:"workDoneProgress,omitempty"`
|
||||
}
|
||||
/**
|
||||
* Experimental client capabilities.
|
||||
*/
|
||||
Experimental interface{} `json:"experimental,omitempty"`
|
||||
/**
|
||||
* Whether implementation supports dynamic registration for selection range providers. If this is set to `true`
|
||||
* the client supports the new `SelectionRangeRegistrationOptions` return value for the corresponding server
|
||||
* capability as well.
|
||||
*/
|
||||
DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
|
||||
}
|
||||
|
||||
/**
|
||||
@ -541,7 +649,8 @@ type CompletionItem struct {
|
||||
InsertText string `json:"insertText,omitempty"`
|
||||
/**
|
||||
* The format of the insert text. The format applies to both the `insertText` property
|
||||
* and the `newText` property of a provided `textEdit`.
|
||||
* and the `newText` property of a provided `textEdit`. If ommitted defaults to
|
||||
* `InsertTextFormat.PlainText`.
|
||||
*/
|
||||
InsertTextFormat InsertTextFormat `json:"insertTextFormat,omitempty"`
|
||||
/**
|
||||
@ -631,6 +740,9 @@ type CompletionOptions struct {
|
||||
* if clients don't support individual commmit characters per completion item. See
|
||||
* `ClientCapabilities.textDocument.completion.completionItem.commitCharactersSupport`
|
||||
*
|
||||
* If a server provides both `allCommitCharacters` and commit characters on an individual
|
||||
* completion item the ones on the completion item win.
|
||||
*
|
||||
* @since 3.2.0
|
||||
*/
|
||||
AllCommitCharacters []string `json:"allCommitCharacters,omitempty"`
|
||||
@ -934,10 +1046,6 @@ type DidChangeConfigurationParams struct {
|
||||
Settings interface{} `json:"settings"`
|
||||
}
|
||||
|
||||
type DidChangeConfigurationRegistrationOptions struct {
|
||||
Section []string /*string | string[]*/ `json:"section,omitempty"`
|
||||
}
|
||||
|
||||
/**
|
||||
* The change text document notification's parameters.
|
||||
*/
|
||||
@ -950,8 +1058,16 @@ type DidChangeTextDocumentParams struct {
|
||||
TextDocument VersionedTextDocumentIdentifier `json:"textDocument"`
|
||||
/**
|
||||
* The actual content changes. The content changes describe single state changes
|
||||
* to the document. So if there are two content changes c1 and c2 for a document
|
||||
* in state S then c1 move the document to S' and c2 to S''.
|
||||
* to the document. So if there are two content changes c1 (at array index 0) and
|
||||
* c2 (at array index 1) for a document in state S then c1 moves the document from
|
||||
* S to S' and c2 from S' to S''. So c1 is computed on the state S and c2 is computed
|
||||
* on the state S'.
|
||||
*
|
||||
* To mirror the content of a document using change events use the following approach:
|
||||
* - start with the same initial content
|
||||
* - apply the 'textDocument/didChange' notifications in the order you recevie them.
|
||||
* - apply the `TextDocumentContentChangeEvent`s in a single notification in the order
|
||||
* you receive them.
|
||||
*/
|
||||
ContentChanges []TextDocumentContentChangeEvent `json:"contentChanges"`
|
||||
}
|
||||
@ -1040,10 +1156,6 @@ type DocumentColorClientCapabilities struct {
|
||||
}
|
||||
|
||||
type DocumentColorOptions struct {
|
||||
/**
|
||||
* Code lens has a resolve provider as well.
|
||||
*/
|
||||
ResolveProvider bool `json:"resolveProvider,omitempty"`
|
||||
WorkDoneProgressOptions
|
||||
}
|
||||
|
||||
@ -2134,6 +2246,13 @@ type PublishDiagnosticsClientCapabilities struct {
|
||||
*/
|
||||
ValueSet []DiagnosticTag `json:"valueSet"`
|
||||
} `json:"tagSupport,omitempty"`
|
||||
/**
|
||||
* Whether the client interprets the version property of the
|
||||
* `textDocument/publishDiagnostics` notification`s parameter.
|
||||
*
|
||||
* @since 3.15.0
|
||||
*/
|
||||
VersionSupport bool `json:"versionSupport,omitempty"`
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2392,6 +2511,90 @@ type SelectionRangeRegistrationOptions struct {
|
||||
StaticRegistrationOptions
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.16.0 - Proposed state
|
||||
*/
|
||||
type SemanticTokens struct {
|
||||
/**
|
||||
* An optional result id. If provided and clients support delta updating
|
||||
* the client will include the result id in the next semantic token request.
|
||||
* A server can then instead of computing all sematic tokens again simply
|
||||
* send a delta.
|
||||
*/
|
||||
ResultID string `json:"resultId,omitempty"`
|
||||
/**
|
||||
* The actual tokens. For a detailed description about how the data is
|
||||
* structured pls see
|
||||
* https://github.com/microsoft/vscode-extension-samples/blob/5ae1f7787122812dcc84e37427ca90af5ee09f14/semantic-tokens-sample/vscode.proposed.d.ts#L71
|
||||
*/
|
||||
Data []float64 `json:"data"`
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.16.0 - Proposed state
|
||||
*/
|
||||
type SemanticTokensEdit struct {
|
||||
Start float64 `json:"start"`
|
||||
DeleteCount float64 `json:"deleteCount"`
|
||||
Data []float64 `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.16.0 - Proposed state
|
||||
*/
|
||||
type SemanticTokensEdits struct {
|
||||
ResultID string `json:"resultId,omitempty"`
|
||||
/**
|
||||
* For a detailed description how these edits are structured pls see
|
||||
* https://github.com/microsoft/vscode-extension-samples/blob/5ae1f7787122812dcc84e37427ca90af5ee09f14/semantic-tokens-sample/vscode.proposed.d.ts#L131
|
||||
*/
|
||||
Edits []SemanticTokensEdit `json:"edits"`
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.16.0 - Proposed state
|
||||
*/
|
||||
type SemanticTokensEditsParams struct {
|
||||
/**
|
||||
* The text document.
|
||||
*/
|
||||
TextDocument TextDocumentIdentifier `json:"textDocument"`
|
||||
/**
|
||||
* The previous result id.
|
||||
*/
|
||||
PreviousResultID string `json:"previousResultId"`
|
||||
WorkDoneProgressParams
|
||||
PartialResultParams
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.16.0 - Proposed state
|
||||
*/
|
||||
type SemanticTokensParams struct {
|
||||
/**
|
||||
* The text document.
|
||||
*/
|
||||
TextDocument TextDocumentIdentifier `json:"textDocument"`
|
||||
WorkDoneProgressParams
|
||||
PartialResultParams
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.16.0 - Proposed state
|
||||
*/
|
||||
type SemanticTokensRangeParams struct {
|
||||
/**
|
||||
* The text document.
|
||||
*/
|
||||
TextDocument TextDocumentIdentifier `json:"textDocument"`
|
||||
/**
|
||||
* The range the semantic tokens are requested for.
|
||||
*/
|
||||
Range Range `json:"range"`
|
||||
WorkDoneProgressParams
|
||||
PartialResultParams
|
||||
}
|
||||
|
||||
type ServerCapabilities = struct {
|
||||
/**
|
||||
* Defines how text documents are synced. Is either a detailed structure defining each notification or
|
||||
@ -2749,15 +2952,10 @@ type SymbolInformation struct {
|
||||
type SymbolKind float64
|
||||
|
||||
/**
|
||||
* Describe options to be used when registered for text document change events.
|
||||
* Symbol tags are extra annotations that tweak the rendering of a symbol.
|
||||
* @since 3.15
|
||||
*/
|
||||
type TextDocumentChangeRegistrationOptions struct {
|
||||
/**
|
||||
* How documents are synced to the server.
|
||||
*/
|
||||
SyncKind TextDocumentSyncKind `json:"syncKind"`
|
||||
TextDocumentRegistrationOptions
|
||||
}
|
||||
type SymbolTag float64
|
||||
|
||||
/**
|
||||
* Text document specific client capabilities.
|
||||
@ -2867,23 +3065,28 @@ type TextDocumentClientCapabilities struct {
|
||||
* An event describing a change to a text document. If range and rangeLength are omitted
|
||||
* the new text is considered to be the full content of the document.
|
||||
*/
|
||||
type TextDocumentContentChangeEvent struct {
|
||||
type TextDocumentContentChangeEvent = struct {
|
||||
/**
|
||||
* The range of the document that changed.
|
||||
*/
|
||||
Range *Range `json:"range,omitempty"`
|
||||
/**
|
||||
* The length of the range that got replaced.
|
||||
* The optional length of the range that got replaced.
|
||||
*
|
||||
* @deprecated use range instead.
|
||||
*/
|
||||
RangeLength float64 `json:"rangeLength,omitempty"`
|
||||
/**
|
||||
* The new text of the document.
|
||||
* The new text for the provided range.
|
||||
*/
|
||||
Text string `json:"text"`
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes textual changes on a text document.
|
||||
* Describes textual changes on a text document. A TextDocumentEdit describes all changes
|
||||
* on a document version Si and after they are applied move the document to version Si+1.
|
||||
* So the creator of a TextDocumentEdit doesn't need to sort the array of edits or do any
|
||||
* kind of ordering. However the edits must be non overlapping.
|
||||
*/
|
||||
type TextDocumentEdit struct {
|
||||
/**
|
||||
@ -2961,14 +3164,6 @@ type TextDocumentRegistrationOptions struct {
|
||||
*/
|
||||
type TextDocumentSaveReason float64
|
||||
|
||||
/**
|
||||
* Save registration options.
|
||||
*/
|
||||
type TextDocumentSaveRegistrationOptions struct {
|
||||
TextDocumentRegistrationOptions
|
||||
SaveOptions
|
||||
}
|
||||
|
||||
type TextDocumentSyncClientCapabilities struct {
|
||||
/**
|
||||
* Whether text document synchronization supports dynamic registration.
|
||||
@ -3126,6 +3321,35 @@ type WillSaveTextDocumentParams struct {
|
||||
Reason TextDocumentSaveReason `json:"reason"`
|
||||
}
|
||||
|
||||
type WorkDoneProgressCancelParams struct {
|
||||
/**
|
||||
* The token to be used to report progress.
|
||||
*/
|
||||
Token ProgressToken `json:"token"`
|
||||
}
|
||||
|
||||
type WorkDoneProgressClientCapabilities struct {
|
||||
/**
|
||||
* Window specific client capabilities.
|
||||
*/
|
||||
Window struct {
|
||||
/**
|
||||
* Whether client supports handling progress notifications. If set servers are allowed to
|
||||
* report in `workDoneProgress` property in the request specific server capabilities.
|
||||
*
|
||||
* Since 3.15.0
|
||||
*/
|
||||
WorkDoneProgress bool `json:"workDoneProgress,omitempty"`
|
||||
} `json:"window,omitempty"`
|
||||
}
|
||||
|
||||
type WorkDoneProgressCreateParams struct {
|
||||
/**
|
||||
* The token to be used to report progress.
|
||||
*/
|
||||
Token ProgressToken `json:"token"`
|
||||
}
|
||||
|
||||
type WorkDoneProgressOptions struct {
|
||||
WorkDoneProgress bool `json:"workDoneProgress,omitempty"`
|
||||
}
|
||||
@ -3222,7 +3446,7 @@ type WorkspaceFolder struct {
|
||||
URI string `json:"uri"`
|
||||
/**
|
||||
* The name of the workspace folder. Used to refer to this
|
||||
* workspace folder in thge user interface.
|
||||
* workspace folder in the user interface.
|
||||
*/
|
||||
Name string `json:"name"`
|
||||
}
|
||||
@ -3374,7 +3598,17 @@ const (
|
||||
* Base kind for an organize imports source action: `source.organizeImports`
|
||||
*/
|
||||
|
||||
SourceOrganizeImports CodeActionKind = "source.organizeImports"
|
||||
SourceOrganizeImports CodeActionKind = "source.organizeImports"
|
||||
/**
|
||||
* Base kind for auto-fix source actions: `source.fixAll`.
|
||||
*
|
||||
* Fix all actions automatically fix errors that have a clear fix that do not require user input.
|
||||
* They should not suppress errors or perform unsafe fixes such as generating new types or classes.
|
||||
*
|
||||
* @since 3.15.0
|
||||
*/
|
||||
|
||||
SourceFixAll CodeActionKind = "source.fixAll"
|
||||
TextCompletion CompletionItemKind = 1
|
||||
MethodCompletion CompletionItemKind = 2
|
||||
FunctionCompletion CompletionItemKind = 3
|
||||
@ -3493,7 +3727,7 @@ const (
|
||||
TextOnlyTransactional FailureHandlingKind = "textOnlyTransactional"
|
||||
/**
|
||||
* The client tries to undo the operations already executed. But there is no
|
||||
* guaruntee that this is succeeding.
|
||||
* guarantee that this is succeeding.
|
||||
*/
|
||||
|
||||
Undo FailureHandlingKind = "undo"
|
||||
@ -3634,6 +3868,11 @@ const (
|
||||
Event SymbolKind = 24
|
||||
Operator SymbolKind = 25
|
||||
TypeParameter SymbolKind = 26
|
||||
/**
|
||||
* Render a symbol as obsolete, usually using a strike-out.
|
||||
*/
|
||||
|
||||
DeprecatedSymbol SymbolTag = 1
|
||||
/**
|
||||
* Manually triggered, e.g. by the user pressing save, by starting debugging,
|
||||
* or by an API call.
|
||||
|
@ -2,8 +2,8 @@ package protocol
|
||||
|
||||
// Package protocol contains data types and code for LSP jsonrpcs
|
||||
// generated automatically from vscode-languageserver-node
|
||||
// commit: 635ab1fe6f8c57ce9402e573d007f24d6d290fd3
|
||||
// last fetched Fri Jan 10 2020 17:17:33 GMT-0500 (Eastern Standard Time)
|
||||
// commit: 7b90c29d0cb5cd7b9c41084f6cb3781a955adeba
|
||||
// last fetched Thu Jan 23 2020 11:10:31 GMT-0500 (Eastern Standard Time)
|
||||
|
||||
// Code generated (see typescript/README.md) DO NOT EDIT.
|
||||
|
||||
@ -18,6 +18,7 @@ import (
|
||||
|
||||
type Server interface {
|
||||
DidChangeWorkspaceFolders(context.Context, *DidChangeWorkspaceFoldersParams) error
|
||||
WorkDoneProgressCancel(context.Context, *WorkDoneProgressCancelParams) error
|
||||
Initialized(context.Context, *InitializedParams) error
|
||||
Exit(context.Context) error
|
||||
DidChangeConfiguration(context.Context, *DidChangeConfigurationParams) error
|
||||
@ -37,6 +38,7 @@ type Server interface {
|
||||
FoldingRange(context.Context, *FoldingRangeParams) ([]FoldingRange /*FoldingRange[] | null*/, error)
|
||||
Declaration(context.Context, *DeclarationParams) (Declaration /*Declaration | DeclarationLink[] | null*/, error)
|
||||
SelectionRange(context.Context, *SelectionRangeParams) ([]SelectionRange /*SelectionRange[] | null*/, error)
|
||||
WorkDoneProgressCreate(context.Context, *WorkDoneProgressCreateParams) error
|
||||
Initialize(context.Context, *ParamInitialize) (*InitializeResult, error)
|
||||
Shutdown(context.Context) error
|
||||
WillSaveWaitUntil(context.Context, *WillSaveTextDocumentParams) ([]TextEdit /*TextEdit[] | null*/, error)
|
||||
@ -60,6 +62,12 @@ type Server interface {
|
||||
Rename(context.Context, *RenameParams) (*WorkspaceEdit /*WorkspaceEdit | null*/, error)
|
||||
PrepareRename(context.Context, *PrepareRenameParams) (interface{} /* Range | struct{; Range Range`json:"range"`; Placeholder string`json:"placeholder"`; } | nil*/, error)
|
||||
ExecuteCommand(context.Context, *ExecuteCommandParams) (interface{} /*any | null*/, error)
|
||||
PrepareCallHierarchy(context.Context, *CallHierarchyPrepareParams) ([]CallHierarchyItem /*CallHierarchyItem[] | null*/, error)
|
||||
IncomingCalls(context.Context, *CallHierarchyIncomingCallsParams) ([]CallHierarchyIncomingCall /*CallHierarchyIncomingCall[] | null*/, error)
|
||||
OutgoingCalls(context.Context, *CallHierarchyOutgoingCallsParams) ([]CallHierarchyOutgoingCall /*CallHierarchyOutgoingCall[] | null*/, error)
|
||||
SemanticTokens(context.Context, *SemanticTokensParams) (*SemanticTokens /*SemanticTokens | null*/, error)
|
||||
SemanticTokensEdits(context.Context, *SemanticTokensEditsParams) (interface{} /* SemanticTokens | SemanticTokensEdits | nil*/, error)
|
||||
SemanticTokensRange(context.Context, *SemanticTokensRangeParams) (*SemanticTokens /*SemanticTokens | null*/, error)
|
||||
NonstandardRequest(ctx context.Context, method string, params interface{}) (interface{}, error)
|
||||
}
|
||||
|
||||
@ -83,6 +91,16 @@ func (h serverHandler) Deliver(ctx context.Context, r *jsonrpc2.Request, deliver
|
||||
log.Error(ctx, "", err)
|
||||
}
|
||||
return true
|
||||
case "window/workDoneProgress/cancel": // notif
|
||||
var params WorkDoneProgressCancelParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, r, err)
|
||||
return true
|
||||
}
|
||||
if err := h.server.WorkDoneProgressCancel(ctx, ¶ms); err != nil {
|
||||
log.Error(ctx, "", err)
|
||||
}
|
||||
return true
|
||||
case "initialized": // notif
|
||||
var params InitializedParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
@ -275,6 +293,17 @@ func (h serverHandler) Deliver(ctx context.Context, r *jsonrpc2.Request, deliver
|
||||
log.Error(ctx, "", err)
|
||||
}
|
||||
return true
|
||||
case "window/workDoneProgress/create": // req
|
||||
var params WorkDoneProgressCreateParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, r, err)
|
||||
return true
|
||||
}
|
||||
err := h.server.WorkDoneProgressCreate(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, nil, err); err != nil {
|
||||
log.Error(ctx, "", err)
|
||||
}
|
||||
return true
|
||||
case "initialize": // req
|
||||
var params ParamInitialize
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
@ -527,6 +556,72 @@ func (h serverHandler) Deliver(ctx context.Context, r *jsonrpc2.Request, deliver
|
||||
log.Error(ctx, "", err)
|
||||
}
|
||||
return true
|
||||
case "textDocument/prepareCallHierarchy": // req
|
||||
var params CallHierarchyPrepareParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, r, err)
|
||||
return true
|
||||
}
|
||||
resp, err := h.server.PrepareCallHierarchy(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
log.Error(ctx, "", err)
|
||||
}
|
||||
return true
|
||||
case "callHierarchy/incomingCalls": // req
|
||||
var params CallHierarchyIncomingCallsParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, r, err)
|
||||
return true
|
||||
}
|
||||
resp, err := h.server.IncomingCalls(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
log.Error(ctx, "", err)
|
||||
}
|
||||
return true
|
||||
case "callHierarchy/outgoingCalls": // req
|
||||
var params CallHierarchyOutgoingCallsParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, r, err)
|
||||
return true
|
||||
}
|
||||
resp, err := h.server.OutgoingCalls(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
log.Error(ctx, "", err)
|
||||
}
|
||||
return true
|
||||
case "textDocument/semanticTokens": // req
|
||||
var params SemanticTokensParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, r, err)
|
||||
return true
|
||||
}
|
||||
resp, err := h.server.SemanticTokens(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
log.Error(ctx, "", err)
|
||||
}
|
||||
return true
|
||||
case "textDocument/semanticTokens/edits": // req
|
||||
var params SemanticTokensEditsParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, r, err)
|
||||
return true
|
||||
}
|
||||
resp, err := h.server.SemanticTokensEdits(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
log.Error(ctx, "", err)
|
||||
}
|
||||
return true
|
||||
case "textDocument/semanticTokens/range": // req
|
||||
var params SemanticTokensRangeParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, r, err)
|
||||
return true
|
||||
}
|
||||
resp, err := h.server.SemanticTokensRange(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
log.Error(ctx, "", err)
|
||||
}
|
||||
return true
|
||||
default:
|
||||
var params interface{}
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
@ -550,6 +645,10 @@ func (s *serverDispatcher) DidChangeWorkspaceFolders(ctx context.Context, params
|
||||
return s.Conn.Notify(ctx, "workspace/didChangeWorkspaceFolders", params)
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) WorkDoneProgressCancel(ctx context.Context, params *WorkDoneProgressCancelParams) error {
|
||||
return s.Conn.Notify(ctx, "window/workDoneProgress/cancel", params)
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) Initialized(ctx context.Context, params *InitializedParams) error {
|
||||
return s.Conn.Notify(ctx, "initialized", params)
|
||||
}
|
||||
@ -653,6 +752,10 @@ func (s *serverDispatcher) SelectionRange(ctx context.Context, params *Selection
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) WorkDoneProgressCreate(ctx context.Context, params *WorkDoneProgressCreateParams) error {
|
||||
return s.Conn.Call(ctx, "window/workDoneProgress/create", params, nil) // Call, not Notify
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) Initialize(ctx context.Context, params *ParamInitialize) (*InitializeResult, error) {
|
||||
var result InitializeResult
|
||||
if err := s.Conn.Call(ctx, "initialize", params, &result); err != nil {
|
||||
@ -833,6 +936,54 @@ func (s *serverDispatcher) ExecuteCommand(ctx context.Context, params *ExecuteCo
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) PrepareCallHierarchy(ctx context.Context, params *CallHierarchyPrepareParams) ([]CallHierarchyItem /*CallHierarchyItem[] | null*/, error) {
|
||||
var result []CallHierarchyItem /*CallHierarchyItem[] | null*/
|
||||
if err := s.Conn.Call(ctx, "textDocument/prepareCallHierarchy", params, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) IncomingCalls(ctx context.Context, params *CallHierarchyIncomingCallsParams) ([]CallHierarchyIncomingCall /*CallHierarchyIncomingCall[] | null*/, error) {
|
||||
var result []CallHierarchyIncomingCall /*CallHierarchyIncomingCall[] | null*/
|
||||
if err := s.Conn.Call(ctx, "callHierarchy/incomingCalls", params, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) OutgoingCalls(ctx context.Context, params *CallHierarchyOutgoingCallsParams) ([]CallHierarchyOutgoingCall /*CallHierarchyOutgoingCall[] | null*/, error) {
|
||||
var result []CallHierarchyOutgoingCall /*CallHierarchyOutgoingCall[] | null*/
|
||||
if err := s.Conn.Call(ctx, "callHierarchy/outgoingCalls", params, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) SemanticTokens(ctx context.Context, params *SemanticTokensParams) (*SemanticTokens /*SemanticTokens | null*/, error) {
|
||||
var result SemanticTokens /*SemanticTokens | null*/
|
||||
if err := s.Conn.Call(ctx, "textDocument/semanticTokens", params, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) SemanticTokensEdits(ctx context.Context, params *SemanticTokensEditsParams) (interface{} /* SemanticTokens | SemanticTokensEdits | nil*/, error) {
|
||||
var result interface{} /* SemanticTokens | SemanticTokensEdits | nil*/
|
||||
if err := s.Conn.Call(ctx, "textDocument/semanticTokens/edits", params, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) SemanticTokensRange(ctx context.Context, params *SemanticTokensRangeParams) (*SemanticTokens /*SemanticTokens | null*/, error) {
|
||||
var result SemanticTokens /*SemanticTokens | null*/
|
||||
if err := s.Conn.Call(ctx, "textDocument/semanticTokens/range", params, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) NonstandardRequest(ctx context.Context, method string, params interface{}) (interface{}, error) {
|
||||
var result interface{}
|
||||
if err := s.Conn.Call(ctx, method, params, &result); err != nil {
|
||||
|
@ -19,15 +19,15 @@
|
||||
import * as fs from 'fs';
|
||||
import * as ts from 'typescript';
|
||||
import * as u from './util';
|
||||
import {constName, getComments, goName, loc, strKind} from './util';
|
||||
import { constName, getComments, goName, loc, strKind } from './util';
|
||||
|
||||
var program: ts.Program;
|
||||
|
||||
function parse() {
|
||||
// this won't complain if some fnames don't exist
|
||||
program = ts.createProgram(
|
||||
u.fnames,
|
||||
{target: ts.ScriptTarget.ES2018, module: ts.ModuleKind.CommonJS});
|
||||
u.fnames,
|
||||
{ target: ts.ScriptTarget.ES2018, module: ts.ModuleKind.CommonJS });
|
||||
program.getTypeChecker(); // finish type checking and assignment
|
||||
}
|
||||
|
||||
@ -35,61 +35,73 @@ function parse() {
|
||||
let req = new Map<string, ts.NewExpression>(); // requests
|
||||
let not = new Map<string, ts.NewExpression>(); // notifications
|
||||
let ptypes = new Map<string, [ts.TypeNode, ts.TypeNode]>(); // req, resp types
|
||||
let receives = new Map<string, 'server'|'client'>(); // who receives it
|
||||
let receives = new Map<string, 'server' | 'client'>(); // who receives it
|
||||
let rpcTypes = new Set<string>(); // types seen in the rpcs
|
||||
|
||||
// walk the AST finding Requests and Notifications
|
||||
function findNews(node: ts.Node) {
|
||||
if (!ts.isNewExpression(node)) {
|
||||
ts.forEachChild(node, findNews)
|
||||
return;
|
||||
function findRPCs(node: ts.Node) {
|
||||
if (!ts.isModuleDeclaration(node)) {
|
||||
return
|
||||
} if (!ts.isIdentifier(node.name)) {
|
||||
throw new Error(`expected Identifier, got ${strKind(node.name)} at ${loc(node)}`)
|
||||
}
|
||||
const wh = node.expression.getText();
|
||||
// We only need the bare ones and the ones ending with 0
|
||||
if (wh != 'RequestType' && wh != 'RequestType0' && wh != 'NotificationType' &&
|
||||
wh != 'NotificationType0')
|
||||
return;
|
||||
if (!node.arguments || node.arguments.length != 1 ||
|
||||
!ts.isStringLiteral(node.arguments[0])) {
|
||||
throw new Error(`expected n.arguments ${loc(node)}`)
|
||||
let reqnot = req
|
||||
let v = node.name.getText()
|
||||
if (v.endsWith('Notification')) reqnot = not;
|
||||
else if (!v.endsWith('Request')) return;
|
||||
|
||||
if (!ts.isModuleBlock(node.body)) {
|
||||
throw new Error(`expected ModuleBody got ${strKind(node.body)} at ${loc(node)}`)
|
||||
}
|
||||
// RequestType<useful>=new RequestTYpe('foo')
|
||||
if (!node.typeArguments) {
|
||||
node.typeArguments = lookUp(node);
|
||||
}
|
||||
// new RequestType<useful>
|
||||
let s = node.arguments[0].getText();
|
||||
// Request or Notification
|
||||
const v = wh[0] == 'R' ? req : not;
|
||||
s = s.substring(1, s.length - 1); // remove quoting (e.g., saw 'exit')
|
||||
v.set(s, node);
|
||||
// Summary:
|
||||
// node.expression == 'RequestType', typeArg[0] is request type,
|
||||
// typeArg[1] is response type, and args[0] is the rpc name
|
||||
// node.espression == 'RequestType0', typeArgs[0] is the response type,
|
||||
// the request type is null, and args[0] is the rpc name
|
||||
// node.expression == 'NotificationType', typeArgs[0] the request, args[0] the
|
||||
// rpc NotificationType0 is the same (but it's always void)
|
||||
const nm = node.expression.getText();
|
||||
const rpc = node.arguments[0].getText();
|
||||
if (nm == 'RequestType' || nm == 'NotificationType') {
|
||||
ptypes.set(rpc, [node.typeArguments[0], node.typeArguments[1]]);
|
||||
} else if (nm == 'RequestType0') {
|
||||
ptypes.set(rpc, [node.typeArguments[0], node.typeArguments[1]]);
|
||||
// that looks the same, but it's a way of getting VoidKeyword
|
||||
} else if (nm == 'NotificationType0') {
|
||||
ptypes.set(rpc, [node.typeArguments[0], node.typeArguments[0]])
|
||||
// both VoidKeyword
|
||||
} else {
|
||||
throw new Error(`FATAL: ${nm} not an expected RPC type`)
|
||||
let x: ts.ModuleBlock = node.body
|
||||
// The story is to expect const method = 'textDocument/implementation'
|
||||
// const type = new ProtocolRequestType<...>(method)
|
||||
// but the method may be an explicit string
|
||||
let rpc: string = '';
|
||||
let newNode: ts.NewExpression;
|
||||
for (let i = 0; i < x.statements.length; i++) {
|
||||
const uu = x.statements[i]
|
||||
if (!ts.isVariableStatement(uu)) continue;
|
||||
const dl: ts.VariableDeclarationList = uu.declarationList
|
||||
if (dl.declarations.length != 1) throw new Error(`expected a single decl at ${loc(dl)}`)
|
||||
const decl: ts.VariableDeclaration = dl.declarations[0]
|
||||
const name = decl.name.getText()
|
||||
// we want the initializers
|
||||
if (name == 'method') { // StringLiteral
|
||||
if (!ts.isStringLiteral(decl.initializer)) throw new Error(`expect StringLiteral at ${loc(decl)}`)
|
||||
rpc = decl.initializer.getText()
|
||||
} else if (name == 'type') { // NewExpression
|
||||
if (!ts.isNewExpression(decl.initializer)) throw new Error(`expecte new at ${loc(decl)}`)
|
||||
const nn: ts.NewExpression = decl.initializer
|
||||
newNode = nn
|
||||
const mtd = nn.arguments[0]
|
||||
if (ts.isStringLiteral(mtd)) rpc = mtd.getText();
|
||||
switch (nn.typeArguments.length) {
|
||||
case 1: // exit
|
||||
ptypes.set(rpc, [nn.typeArguments[0], null])
|
||||
break;
|
||||
case 2: // notifications
|
||||
ptypes.set(rpc, [nn.typeArguments[0], null])
|
||||
break;
|
||||
case 4:// request with no parameters
|
||||
ptypes.set(rpc, [null, nn.typeArguments[0]])
|
||||
break;
|
||||
case 5: // request req, resp, partial(?)
|
||||
ptypes.set(rpc, [nn.typeArguments[0], nn.typeArguments[1]])
|
||||
break;
|
||||
default: throw new Error(`${nn.typeArguments.length} at ${loc(nn)}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (rpc == '') throw new Error(`no name found at ${loc(x)}`)
|
||||
// remember the implied types
|
||||
const [a, b] = ptypes.get(rpc);
|
||||
const add = function(n: ts.Node) {
|
||||
const add = function (n: ts.Node) {
|
||||
rpcTypes.add(goName(n.getText()))
|
||||
};
|
||||
underlying(a, add);
|
||||
underlying(b, add);
|
||||
rpc = rpc.substring(1, rpc.length - 1) // 'exit'
|
||||
reqnot.set(rpc, newNode)
|
||||
}
|
||||
|
||||
// handle missing typeArguments
|
||||
@ -110,8 +122,8 @@ function setReceives() {
|
||||
// it would be nice to have some independent check on this
|
||||
// (this logic fails if the server ever sends $/canceRequest
|
||||
// or $/progress)
|
||||
req.forEach((_, k) => {receives.set(k, 'server')});
|
||||
not.forEach((_, k) => {receives.set(k, 'server')});
|
||||
req.forEach((_, k) => { receives.set(k, 'server') });
|
||||
not.forEach((_, k) => { receives.set(k, 'server') });
|
||||
receives.set('window/showMessage', 'client');
|
||||
receives.set('window/showMessageRequest', 'client');
|
||||
receives.set('window/logMessage', 'client');
|
||||
@ -146,22 +158,22 @@ interface Data {
|
||||
function newData(n: ts.Node, nm: string): Data {
|
||||
return {
|
||||
me: n, name: goName(nm),
|
||||
generics: ts.createNodeArray<ts.TypeParameterDeclaration>(), as: ts.createNodeArray<ts.HeritageClause>(),
|
||||
properties: ts.createNodeArray<ts.TypeElement>(), alias: undefined,
|
||||
statements: ts.createNodeArray<ts.Statement>(),
|
||||
enums: ts.createNodeArray<ts.EnumMember>(),
|
||||
members: ts.createNodeArray<ts.PropertyDeclaration>(),
|
||||
generics: ts.createNodeArray<ts.TypeParameterDeclaration>(), as: ts.createNodeArray<ts.HeritageClause>(),
|
||||
properties: ts.createNodeArray<ts.TypeElement>(), alias: undefined,
|
||||
statements: ts.createNodeArray<ts.Statement>(),
|
||||
enums: ts.createNodeArray<ts.EnumMember>(),
|
||||
members: ts.createNodeArray<ts.PropertyDeclaration>(),
|
||||
}
|
||||
}
|
||||
|
||||
// for debugging, produce a skeleton description
|
||||
function strData(d: Data): string {
|
||||
const f = function(na: ts.NodeArray<any>): number {
|
||||
const f = function (na: ts.NodeArray<any>): number {
|
||||
return na.length
|
||||
};
|
||||
return `D(${d.name}) g;${f(d.generics)} a:${f(d.as)} p:${f(d.properties)} s:${
|
||||
f(d.statements)} e:${f(d.enums)} m:${f(d.members)} ${
|
||||
d.alias != undefined}`
|
||||
f(d.statements)} e:${f(d.enums)} m:${f(d.members)} ${
|
||||
d.alias != undefined}`
|
||||
}
|
||||
|
||||
let data = new Map<string, Data>(); // parsed data types
|
||||
@ -172,16 +184,16 @@ let extraTypes = new Map<string, string[]>(); // to avoid struct params
|
||||
function genTypes(node: ts.Node) {
|
||||
// Ignore top-level items that can't produce output
|
||||
if (ts.isExpressionStatement(node) || ts.isFunctionDeclaration(node) ||
|
||||
ts.isImportDeclaration(node) || ts.isVariableStatement(node) ||
|
||||
ts.isExportDeclaration(node) || ts.isEmptyStatement(node) ||
|
||||
node.kind == ts.SyntaxKind.EndOfFileToken) {
|
||||
ts.isImportDeclaration(node) || ts.isVariableStatement(node) ||
|
||||
ts.isExportDeclaration(node) || ts.isEmptyStatement(node) ||
|
||||
node.kind == ts.SyntaxKind.EndOfFileToken) {
|
||||
return;
|
||||
}
|
||||
if (ts.isInterfaceDeclaration(node)) {
|
||||
const v: ts.InterfaceDeclaration = node;
|
||||
// need to check the members, many of which are disruptive
|
||||
let mems: ts.TypeElement[] = [];
|
||||
const f = function(t: ts.TypeElement) {
|
||||
const f = function (t: ts.TypeElement) {
|
||||
if (ts.isPropertySignature(t)) {
|
||||
mems.push(t);
|
||||
} else if (ts.isMethodSignature(t) || ts.isCallSignatureDeclaration(t)) {
|
||||
@ -196,7 +208,7 @@ function genTypes(node: ts.Node) {
|
||||
};
|
||||
v.members.forEach(f);
|
||||
if (mems.length == 0 && !v.heritageClauses &&
|
||||
v.name.getText() != 'InitializedParams') {
|
||||
v.name.getText() != 'InitializedParams') {
|
||||
return // really? (Don't seem to need any of these)
|
||||
};
|
||||
// Found one we want
|
||||
@ -220,7 +232,7 @@ function genTypes(node: ts.Node) {
|
||||
// (at the top level)
|
||||
// Unfortunately this is false for TraceValues
|
||||
if (ts.isUnionTypeNode(v.type) &&
|
||||
v.type.types.every((n: ts.TypeNode) => ts.isLiteralTypeNode(n))) {
|
||||
v.type.types.every((n: ts.TypeNode) => ts.isLiteralTypeNode(n))) {
|
||||
if (x.name != 'TraceValues') return;
|
||||
}
|
||||
if (v.typeParameters) {
|
||||
@ -239,15 +251,15 @@ function genTypes(node: ts.Node) {
|
||||
const b: ts.ModuleBlock = v.body;
|
||||
var s: ts.Statement[] = [];
|
||||
// we don't want most of these
|
||||
const fx = function(x: ts.Statement) {
|
||||
const fx = function (x: ts.Statement) {
|
||||
if (ts.isFunctionDeclaration(x)) {
|
||||
return
|
||||
};
|
||||
if (ts.isTypeAliasDeclaration(x)) {
|
||||
if (ts.isTypeAliasDeclaration(x) || ts.isModuleDeclaration(x)) {
|
||||
return
|
||||
};
|
||||
if (!ts.isVariableStatement(x))
|
||||
throw new Error(`${loc(x)} ${strKind(x)}`);
|
||||
throw new Error(`expected VariableStatment ${loc(x)} ${strKind(x)} ${x.getText()}`);
|
||||
if (hasNewExpression(x)) {
|
||||
return
|
||||
};
|
||||
@ -273,7 +285,7 @@ function genTypes(node: ts.Node) {
|
||||
const v: ts.ClassDeclaration = node;
|
||||
var d: ts.PropertyDeclaration[] = [];
|
||||
// look harder at the PropertyDeclarations.
|
||||
const wanted = function(c: ts.ClassElement): string {
|
||||
const wanted = function (c: ts.ClassElement): string {
|
||||
if (ts.isConstructorDeclaration(c)) {
|
||||
return ''
|
||||
};
|
||||
@ -309,7 +321,7 @@ function genTypes(node: ts.Node) {
|
||||
}
|
||||
if (data.has(c.name))
|
||||
throw new Error(`Class dup ${loc(c.me)} and ${loc(data.get(c.name).me)}`)
|
||||
data.set(c.name, c);
|
||||
data.set(c.name, c);
|
||||
} else {
|
||||
throw new Error(`unexpected ${strKind(node)} ${loc(node)} `)
|
||||
}
|
||||
@ -322,20 +334,26 @@ function dataMerge(a: Data, b: Data): Data {
|
||||
if (at == bt) {
|
||||
return a;
|
||||
}
|
||||
const ax = `(${a.statements.length},${a.properties.length})`
|
||||
const bx = `(${b.statements.length},${b.properties.length})`
|
||||
//console.log(`397 ${a.name}${ax}${bx}\n${a.me.getText()}\n${b.me.getText()}\n`)
|
||||
switch (a.name) {
|
||||
case 'InitializeError':
|
||||
case 'MessageType':
|
||||
case 'CompletionItemTag':
|
||||
case 'SymbolTag':
|
||||
case 'CodeActionKind':
|
||||
// want the Module
|
||||
return a.statements.length > 0 ? a : b;
|
||||
case 'CancellationToken':
|
||||
// want the Interface
|
||||
return a.properties.length > 0 ? a : b;
|
||||
case 'TextDocumentContentChangeEvent': // almost the same
|
||||
return a;
|
||||
}
|
||||
console.log(
|
||||
`${strKind(a.me)} ${strKind(b.me)} ${a.name} ${loc(a.me)} ${loc(b.me)}`)
|
||||
throw new Error(`Fix dataMerge`)
|
||||
`${strKind(a.me)} ${strKind(b.me)} ${a.name} ${loc(a.me)} ${loc(b.me)}`)
|
||||
throw new Error(`Fix dataMerge for ${a.name}`)
|
||||
}
|
||||
|
||||
// is a node an ancestor of a NewExpression
|
||||
@ -357,19 +375,19 @@ function checkOnce() {
|
||||
// helper function to find underlying types
|
||||
function underlying(n: ts.Node, f: (n: ts.Node) => void) {
|
||||
if (!n) return;
|
||||
const ff = function(n: ts.Node) {
|
||||
const ff = function (n: ts.Node) {
|
||||
underlying(n, f)
|
||||
};
|
||||
if (ts.isIdentifier(n)) {
|
||||
f(n)
|
||||
} else if (
|
||||
n.kind == ts.SyntaxKind.StringKeyword ||
|
||||
n.kind == ts.SyntaxKind.NumberKeyword ||
|
||||
n.kind == ts.SyntaxKind.AnyKeyword ||
|
||||
n.kind == ts.SyntaxKind.NullKeyword ||
|
||||
n.kind == ts.SyntaxKind.BooleanKeyword ||
|
||||
n.kind == ts.SyntaxKind.ObjectKeyword ||
|
||||
n.kind == ts.SyntaxKind.VoidKeyword) {
|
||||
n.kind == ts.SyntaxKind.StringKeyword ||
|
||||
n.kind == ts.SyntaxKind.NumberKeyword ||
|
||||
n.kind == ts.SyntaxKind.AnyKeyword ||
|
||||
n.kind == ts.SyntaxKind.NullKeyword ||
|
||||
n.kind == ts.SyntaxKind.BooleanKeyword ||
|
||||
n.kind == ts.SyntaxKind.ObjectKeyword ||
|
||||
n.kind == ts.SyntaxKind.VoidKeyword) {
|
||||
// nothing to do
|
||||
} else if (ts.isTypeReferenceNode(n)) {
|
||||
f(n.typeName)
|
||||
@ -390,8 +408,8 @@ function underlying(n: ts.Node, f: (n: ts.Node) => void) {
|
||||
} else if (ts.isParenthesizedTypeNode(n)) {
|
||||
underlying(n.type, f)
|
||||
} else if (
|
||||
ts.isLiteralTypeNode(n) || ts.isVariableStatement(n) ||
|
||||
ts.isTupleTypeNode(n)) {
|
||||
ts.isLiteralTypeNode(n) || ts.isVariableStatement(n) ||
|
||||
ts.isTupleTypeNode(n)) {
|
||||
// we only see these in moreTypes, but they are handled elsewhere
|
||||
return;
|
||||
} else if (ts.isEnumMember(n)) {
|
||||
@ -406,31 +424,34 @@ function underlying(n: ts.Node, f: (n: ts.Node) => void) {
|
||||
// Simplest way to the transitive closure is to stabilize the size of seenTypes
|
||||
// but it is slow
|
||||
function moreTypes() {
|
||||
const extra = function(s: string) {
|
||||
const extra = function (s: string) {
|
||||
if (!data.has(s)) throw new Error(`moreTypes needs ${s}`)
|
||||
seenTypes.set(s, data.get(s))
|
||||
seenTypes.set(s, data.get(s))
|
||||
};
|
||||
rpcTypes.forEach(extra); // all the types needed by the rpcs
|
||||
// needed in enums.go (or elsewhere)
|
||||
extra('InitializeError')
|
||||
extra('WatchKind')
|
||||
extra('FoldingRangeKind')
|
||||
// not sure why these weren't picked up
|
||||
extra('FileSystemWatcher')
|
||||
extra('DidChangeWatchedFilesRegistrationOptions')
|
||||
let old = 0
|
||||
do {
|
||||
old = seenTypes.size
|
||||
|
||||
const m = new Map<string, Data>();
|
||||
const add = function(n: ts.Node) {
|
||||
const add = function (n: ts.Node) {
|
||||
const nm = goName(n.getText());
|
||||
if (seenTypes.has(nm) || m.has(nm)) return;
|
||||
// For generic parameters, this might set it to undefined
|
||||
m.set(nm, data.get(nm));
|
||||
};
|
||||
// expect all the heritage clauses have single Identifiers
|
||||
const h = function(n: ts.Node) {
|
||||
const h = function (n: ts.Node) {
|
||||
underlying(n, add);
|
||||
};
|
||||
const f = function(x: ts.NodeArray<ts.Node>) {
|
||||
const f = function (x: ts.NodeArray<ts.Node>) {
|
||||
x.forEach(h)
|
||||
};
|
||||
seenTypes.forEach((d: Data) => d && f(d.as))
|
||||
@ -459,11 +480,11 @@ function toGo(d: Data, nm: string) {
|
||||
} else if (d.enums.length > 0) {
|
||||
goEnum(d, nm);
|
||||
} else if (
|
||||
d.properties.length > 0 || d.as.length > 0 || nm == 'InitializedParams') {
|
||||
d.properties.length > 0 || d.as.length > 0 || nm == 'InitializedParams') {
|
||||
goInterface(d, nm);
|
||||
} else
|
||||
throw new Error(
|
||||
`more cases in toGo ${nm} ${d.as.length} ${d.generics.length} `)
|
||||
`more cases in toGo ${nm} ${d.as.length} ${d.generics.length} `)
|
||||
}
|
||||
|
||||
// these fields need a *
|
||||
@ -478,7 +499,7 @@ function goInterface(d: Data, nm: string) {
|
||||
let ans = `type ${goName(nm)} struct {\n`;
|
||||
|
||||
// generate the code for each member
|
||||
const g = function(n: ts.TypeElement) {
|
||||
const g = function (n: ts.TypeElement) {
|
||||
if (!ts.isPropertySignature(n))
|
||||
throw new Error(`expected PropertySignature got ${strKind(n)} `);
|
||||
ans = ans.concat(getComments(n));
|
||||
@ -495,7 +516,7 @@ function goInterface(d: Data, nm: string) {
|
||||
d.properties.forEach(g)
|
||||
// heritage clauses become embedded types
|
||||
// check they are all Identifiers
|
||||
const f = function(n: ts.ExpressionWithTypeArguments) {
|
||||
const f = function (n: ts.ExpressionWithTypeArguments) {
|
||||
if (!ts.isIdentifier(n.expression))
|
||||
throw new Error(`Interface ${nm} heritage ${strKind(n.expression)} `);
|
||||
ans = ans.concat(goName(n.expression.getText()), '\n')
|
||||
@ -518,7 +539,7 @@ function goModule(d: Data, nm: string) {
|
||||
// They are VariableStatements with x.declarationList having a single
|
||||
// VariableDeclaration
|
||||
let isNumeric = false;
|
||||
const f = function(n: ts.Statement, i: number) {
|
||||
const f = function (n: ts.Statement, i: number) {
|
||||
if (!ts.isVariableStatement(n)) {
|
||||
throw new Error(` ${nm} ${i} expected VariableStatement,
|
||||
got ${strKind(n)}`);
|
||||
@ -545,7 +566,7 @@ function goModule(d: Data, nm: string) {
|
||||
// generate Go code for an enum. Both types and named constants
|
||||
function goEnum(d: Data, nm: string) {
|
||||
let isNumeric = false
|
||||
const f = function(v: ts.EnumMember, j: number) { // same as goModule
|
||||
const f = function (v: ts.EnumMember, j: number) { // same as goModule
|
||||
if (!v.initializer)
|
||||
throw new Error(`goEnum no initializer ${nm} ${j} ${v.name.getText()}`);
|
||||
isNumeric = strKind(v.initializer) == 'NumericLiteral';
|
||||
@ -566,7 +587,7 @@ function goTypeAlias(d: Data, nm: string) {
|
||||
if (d.as.length != 0 || d.generics.length != 0) {
|
||||
if (nm != 'ServerCapabilities')
|
||||
throw new Error(`${nm} has extra fields(${d.as.length},${
|
||||
d.generics.length}) ${d.me.getText()}`);
|
||||
d.generics.length}) ${d.me.getText()}`);
|
||||
}
|
||||
typesOut.push(getComments(d.me))
|
||||
// d.alias doesn't seem to have comments
|
||||
@ -592,7 +613,7 @@ function goType(n: ts.TypeNode, nm: string): string {
|
||||
return 'interface{}';
|
||||
} else if (strKind(n) == 'NullKeyword') {
|
||||
return 'nil'
|
||||
} else if (strKind(n) == 'VoidKeyword') {
|
||||
} else if (strKind(n) == 'VoidKeyword' || strKind(n) == 'NeverKeyword') {
|
||||
return 'void'
|
||||
} else if (strKind(n) == 'ObjectKeyword') {
|
||||
return 'interface{}'
|
||||
@ -608,9 +629,9 @@ function goType(n: ts.TypeNode, nm: string): string {
|
||||
return v
|
||||
} else if (ts.isTupleTypeNode(n)) {
|
||||
if (n.getText() == '[number, number]') return '[]float64'
|
||||
throw new Error(`goType undexpected Tuple ${n.getText()}`)
|
||||
throw new Error(`goType unexpected Tuple ${n.getText()}`)
|
||||
}
|
||||
throw new Error(`${strKind(n)} goType unexpected ${n.getText()}`)
|
||||
throw new Error(`${strKind(n)} goType unexpected ${n.getText()} for ${nm}`)
|
||||
}
|
||||
|
||||
// The choice is uniform interface{}, or some heuristically assigned choice,
|
||||
@ -641,11 +662,13 @@ function goUnionType(n: ts.UnionTypeNode, nm: string): string {
|
||||
return `${goType(n.types[0], 'b')} ${help}`
|
||||
}
|
||||
if (b == 'ArrayType') return `${goType(n.types[1], 'c')} ${help}`
|
||||
if (a == 'TypeReference' && a == b) return `interface{} ${help}`
|
||||
if (a == 'StringKeyword') // too gross
|
||||
return `string ${help}`;
|
||||
throw new Error(`612 ${strKind(n.types[0])} ${strKind(n.types[1])}`)
|
||||
case 3: const aa = strKind(n.types[0])
|
||||
if (a == 'TypeReference' && a == b) return `interface{} ${help}`
|
||||
if (a == 'StringKeyword') return `string ${help}`;
|
||||
if (a == 'TypeLiteral' && nm == 'TextDocumentContentChangeEvent') {
|
||||
return `${goType(n.types[0], nm)}`
|
||||
}
|
||||
throw new Error(`724 ${a} ${b} ${n.getText()} ${loc(n)}`)
|
||||
case 3: const aa = strKind(n.types[0])
|
||||
const bb = strKind(n.types[1])
|
||||
const cc = strKind(n.types[2])
|
||||
if (nm == 'DocumentFilter') {
|
||||
@ -668,7 +691,7 @@ function goUnionType(n: ts.UnionTypeNode, nm: string): string {
|
||||
return `${goType(n.types[1], 'f')} ${help}`
|
||||
}
|
||||
if (aa == 'LiteralType' && bb == aa && cc == aa) return `string ${help}`
|
||||
break;
|
||||
break;
|
||||
case 4:
|
||||
if (nm == 'documentChanges') return `TextDocumentEdit ${help} `;
|
||||
default:
|
||||
@ -708,7 +731,7 @@ function goIntersectionType(n: ts.IntersectionTypeNode, nm: string): string {
|
||||
if (nm == 'ServerCapabilities') return expandIntersection(n);
|
||||
let inner = '';
|
||||
n.types.forEach(
|
||||
(t: ts.TypeNode) => {inner = inner.concat(goType(t, nm), '\n')});
|
||||
(t: ts.TypeNode) => { inner = inner.concat(goType(t, nm), '\n') });
|
||||
return `struct{ \n${inner}} `
|
||||
}
|
||||
|
||||
@ -717,7 +740,7 @@ function goIntersectionType(n: ts.IntersectionTypeNode, nm: string): string {
|
||||
// of them by name. The names that occur once can be output. The names
|
||||
// that occur more than once need to be combined.
|
||||
function expandIntersection(n: ts.IntersectionTypeNode): string {
|
||||
const bad = function(n: ts.Node, s: string) {
|
||||
const bad = function (n: ts.Node, s: string) {
|
||||
return new Error(`expandIntersection ${strKind(n)} ${s}`)
|
||||
};
|
||||
let props = new Map<string, ts.PropertySignature[]>();
|
||||
@ -751,9 +774,12 @@ function expandIntersection(n: ts.IntersectionTypeNode): string {
|
||||
if (!ts.isPropertySignature(b)) throw bad(b, 'D');
|
||||
ans = ans.concat(getComments(b));
|
||||
ans = ans.concat(
|
||||
goName(b.name.getText()), ' ', goType(b.type, 'a'), u.JSON(b), '\n')
|
||||
goName(b.name.getText()), ' ', goType(b.type, 'a'), u.JSON(b), '\n')
|
||||
} else if (a.type.kind == ts.SyntaxKind.ObjectKeyword) {
|
||||
ans = ans.concat(getComments(a))
|
||||
ans = ans.concat(goName(a.name.getText()), ' ', 'interface{}', u.JSON(a), '\n')
|
||||
} else {
|
||||
throw bad(a.type, 'E')
|
||||
throw bad(a.type, `E ${a.getText()} in ${goName(k)} at ${loc(a)}`)
|
||||
}
|
||||
}
|
||||
ans = ans.concat('}\n');
|
||||
@ -764,13 +790,18 @@ function expandIntersection(n: ts.IntersectionTypeNode): string {
|
||||
|
||||
function goTypeLiteral(n: ts.TypeLiteralNode, nm: string): string {
|
||||
let ans: string[] = []; // in case we generate a new extra type
|
||||
let res = 'struct{\n'
|
||||
const g = function(nx: ts.TypeElement) {
|
||||
let res = 'struct{\n' // the actual answer usually
|
||||
const g = function (nx: ts.TypeElement) {
|
||||
// add the json, as in goInterface(). Strange inside union types.
|
||||
if (ts.isPropertySignature(nx)) {
|
||||
const json = u.JSON(nx);
|
||||
const typ = goType(nx.type, nx.name.getText())
|
||||
let json = u.JSON(nx);
|
||||
let typ = goType(nx.type, nx.name.getText())
|
||||
const v = getComments(nx) || '';
|
||||
starred.forEach(([a, b]) => {
|
||||
if (a != nm || b != typ.toLowerCase()) return;
|
||||
typ = '*' + typ;
|
||||
json = json.substring(0, json.length - 2) + ',omitempty"`'
|
||||
})
|
||||
res = res.concat(`${v} ${goName(nx.name.getText())} ${typ}`, json, '\n')
|
||||
ans.push(`${v}${goName(nx.name.getText())} ${typ} ${json}\n`)
|
||||
} else if (ts.isIndexSignatureDeclaration(nx)) {
|
||||
@ -894,20 +925,23 @@ function goNot(side: side, m: string) {
|
||||
function goReq(side: side, m: string) {
|
||||
const n = req.get(m);
|
||||
const nm = methodName(m);
|
||||
if (nm.indexOf('/') >= 0) {
|
||||
console.log(`980 ${m} ${n.getText()} ${loc(n)} `)
|
||||
}
|
||||
let a = goType(n.typeArguments[0], m);
|
||||
let b = goType(n.typeArguments[1], m);
|
||||
if (n.getText().includes('Type0')) {
|
||||
b = a;
|
||||
a = ''; // workspace/workspaceFolders and shutdown
|
||||
}
|
||||
u.prb(`${side.name} req ${a != ''},${b != ''} ${nm} ${m} ${loc(n)}`)
|
||||
u.prb(`${side.name} req ${a != ''}, ${b != ''} ${nm} ${m} ${loc(n)} `)
|
||||
side.methods.push(sig(nm, a, b));
|
||||
|
||||
const caseHdr = `case "${m}": // req`;
|
||||
let case1 = notNil;
|
||||
if (a != '') {
|
||||
if (extraTypes.has('Param' + nm)) a = 'Param' + nm
|
||||
case1 = `var params ${a}
|
||||
case1 = `var params ${a}
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, r, err)
|
||||
return true
|
||||
@ -941,7 +975,7 @@ function goReq(side: side, m: string) {
|
||||
if (indirect(b)) theRet = '&result';
|
||||
callBody = `var result ${b}
|
||||
if err := s.Conn.Call(ctx, "${m}", ${
|
||||
p2}, &result); err != nil {
|
||||
p2}, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ${theRet}, nil
|
||||
@ -956,11 +990,20 @@ function goReq(side: side, m: string) {
|
||||
// make sure method names are unique
|
||||
let seenNames = new Set<string>();
|
||||
function methodName(m: string): string {
|
||||
const i = m.indexOf('/');
|
||||
let i = m.indexOf('/');
|
||||
let s = m.substring(i + 1);
|
||||
let x = s[0].toUpperCase() + s.substring(1);
|
||||
const j = x.indexOf('/')
|
||||
if (j >= 0) {
|
||||
let suffix = x.substring(j + 1)
|
||||
suffix = suffix[0].toUpperCase() + suffix.substring(1)
|
||||
let prefix = x.substring(0, j)
|
||||
x = prefix + suffix
|
||||
}
|
||||
if (seenNames.has(x)) {
|
||||
x += m[0].toUpperCase() + m.substring(1, i);
|
||||
// Resolve, ResolveCodeLens, ResolveDocumentLink
|
||||
if (!x.startsWith('Resolve')) throw new Error(`expected Resolve, not ${x}`)
|
||||
x += m[0].toUpperCase() + m.substring(1, i)
|
||||
}
|
||||
seenNames.add(x);
|
||||
return x;
|
||||
@ -971,7 +1014,7 @@ function indirect(s: string): boolean {
|
||||
if (s == '' || s == 'void') return false;
|
||||
const skip = (x: string) => s.startsWith(x);
|
||||
if (skip('[]') || skip('interface') || skip('Declaration') ||
|
||||
skip('Definition') || skip('DocumentSelector'))
|
||||
skip('Definition') || skip('DocumentSelector'))
|
||||
return false;
|
||||
return true
|
||||
}
|
||||
@ -1011,7 +1054,7 @@ function output(side: side) {
|
||||
side.outputFile = `ts${side.name}.go`;
|
||||
side.fd = fs.openSync(side.outputFile, 'w');
|
||||
}
|
||||
const f = function(s: string) {
|
||||
const f = function (s: string) {
|
||||
fs.writeSync(side.fd, s);
|
||||
fs.writeSync(side.fd, '\n');
|
||||
};
|
||||
@ -1028,10 +1071,10 @@ function output(side: side) {
|
||||
`);
|
||||
const a = side.name[0].toUpperCase() + side.name.substring(1)
|
||||
f(`type ${a} interface {`);
|
||||
side.methods.forEach((v) => {f(v)});
|
||||
side.methods.forEach((v) => { f(v) });
|
||||
f('}\n');
|
||||
f(`func (h ${
|
||||
side.name}Handler) Deliver(ctx context.Context, r *jsonrpc2.Request, delivered bool) bool {
|
||||
side.name}Handler) Deliver(ctx context.Context, r *jsonrpc2.Request, delivered bool) bool {
|
||||
if delivered {
|
||||
return false
|
||||
}
|
||||
@ -1041,7 +1084,7 @@ function output(side: side) {
|
||||
return true
|
||||
}
|
||||
switch r.Method {`);
|
||||
side.cases.forEach((v) => {f(v)});
|
||||
side.cases.forEach((v) => { f(v) });
|
||||
f(`
|
||||
}
|
||||
}`);
|
||||
@ -1050,7 +1093,7 @@ function output(side: side) {
|
||||
*jsonrpc2.Conn
|
||||
}
|
||||
`);
|
||||
side.calls.forEach((v) => {f(v)});
|
||||
side.calls.forEach((v) => { f(v) });
|
||||
}
|
||||
|
||||
// Handling of non-standard requests, so we can add gopls-specific calls.
|
||||
@ -1084,16 +1127,15 @@ function nonstandardRequests() {
|
||||
function main() {
|
||||
if (u.gitHash != u.git()) {
|
||||
throw new Error(
|
||||
`git hash mismatch, wanted\n${u.gitHash} but source is at\n${u.git()}`);
|
||||
`git hash mismatch, wanted\n${u.gitHash} but source is at\n${u.git()}`);
|
||||
}
|
||||
u.createOutputFiles()
|
||||
parse()
|
||||
u.printAST(program)
|
||||
// visit every sourceFile in the program, collecting the New
|
||||
// nodes that encapsulate the protocol
|
||||
// find the Requests and Nofificatations
|
||||
for (const sourceFile of program.getSourceFiles()) {
|
||||
if (!sourceFile.isDeclarationFile) {
|
||||
ts.forEachChild(sourceFile, findNews)
|
||||
ts.forEachChild(sourceFile, findRPCs)
|
||||
}
|
||||
}
|
||||
// separate RPCs into client and server
|
||||
@ -1112,11 +1154,13 @@ function main() {
|
||||
// 2. func (h *serverHandler) Deliver(...) { switch r.method }
|
||||
// 3. func (x *xDispatcher) Method(ctx, parm)
|
||||
not.forEach( // notifications
|
||||
(v, k) => {
|
||||
receives.get(k) == 'client' ? goNot(client, k) : goNot(server, k)});
|
||||
(v, k) => {
|
||||
receives.get(k) == 'client' ? goNot(client, k) : goNot(server, k)
|
||||
});
|
||||
req.forEach( // requests
|
||||
(v, k) => {
|
||||
receives.get(k) == 'client' ? goReq(client, k) : goReq(server, k)});
|
||||
(v, k) => {
|
||||
receives.get(k) == 'client' ? goReq(client, k) : goReq(server, k)
|
||||
});
|
||||
nonstandardRequests();
|
||||
// find all the types implied by seenTypes and rpcs to try to avoid
|
||||
// generating types that aren't used
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,521 +0,0 @@
|
||||
import * as fs from 'fs';
|
||||
import * as ts from 'typescript';
|
||||
|
||||
// generate tsclient.go and tsserver.go, which are the definitions and stubs for
|
||||
// supporting the LPS protocol. These files have 3 sections:
|
||||
// 1. define the Client or Server type
|
||||
// 2. fill out the clientHandler or serveHandler which is basically a large
|
||||
// switch on the requests and notifications received by the client/server.
|
||||
// 3. The methods corresponding to these. (basically parse the request,
|
||||
// call something, and perhaps send a response.)
|
||||
|
||||
let dir = process.env['HOME'];
|
||||
let fnames = [
|
||||
`/vscode-languageserver-node/protocol/src/protocol.ts`,
|
||||
`/vscode-languageserver-node/jsonrpc/src/main.ts`
|
||||
];
|
||||
|
||||
let fda: number, fdy: number; // file descriptors
|
||||
|
||||
function createOutputFiles() {
|
||||
fda = fs.openSync('/tmp/ts-a', 'w') // dump of AST
|
||||
fdy = fs.openSync('/tmp/ts-c', 'w') // unused, for debugging
|
||||
}
|
||||
function pra(s: string) {
|
||||
return (fs.writeSync(fda, s))
|
||||
}
|
||||
function prb(s: string) {
|
||||
return (fs.writeSync(fdy, s + '\n'))
|
||||
}
|
||||
|
||||
let program: ts.Program;
|
||||
|
||||
function generate(files: string[], options: ts.CompilerOptions): void {
|
||||
program = ts.createProgram(files, options);
|
||||
program.getTypeChecker();
|
||||
|
||||
dumpAST(); // for debugging
|
||||
|
||||
// visit every sourceFile in the program, collecting information
|
||||
for (const sourceFile of program.getSourceFiles()) {
|
||||
if (!sourceFile.isDeclarationFile) {
|
||||
ts.forEachChild(sourceFile, genStuff)
|
||||
}
|
||||
}
|
||||
// when 4 args, they are param, result, error, registration options, e.g.:
|
||||
// RequestType<TextDocumentPositionParams, Definition | DefinitionLink[] |
|
||||
// null,
|
||||
// void, TextDocumentRegistrationOptions>('textDocument/implementation');
|
||||
// 3 args is RequestType0('shutdown')<void, void, void>
|
||||
// and RequestType0('workspace/workspaceFolders)<WorkspaceFolder[]|null, void,
|
||||
// void>
|
||||
|
||||
// the two args are the notification data and the registration data
|
||||
// except for textDocument/selectionRange and a NotificationType0('exit')
|
||||
// selectionRange is the following, but for now do it by hand, special case.
|
||||
// RequestType<TextDocumentPositionParams, SelectionRange[] | null, any, any>
|
||||
// = new RequestType('textDocument/selectionRange')
|
||||
// and foldingRange has the same problem.
|
||||
|
||||
setReceives(); // distinguish client and server
|
||||
// for each of Client and Server there are 3 parts to the output:
|
||||
// 1. type X interface {methods}
|
||||
// 2. func (h *serverHandler) Deliver(...) { switch r.method }
|
||||
// 3. func (x *xDispatcher) Method(ctx, parm)
|
||||
not.forEach(
|
||||
(v, k) => {receives.get(k) == 'client' ? goNot(client, k) :
|
||||
goNot(server, k)});
|
||||
req.forEach(
|
||||
(v, k) => {receives.get(k) == 'client' ? goReq(client, k) :
|
||||
goReq(server, k)});
|
||||
// and print the Go code
|
||||
output(client);
|
||||
output(server);
|
||||
return;
|
||||
}
|
||||
|
||||
// Go signatures for methods.
|
||||
function sig(nm: string, a: string, b: string, names?: boolean): string {
|
||||
if (a != '') {
|
||||
if (names)
|
||||
a = ', params *' + a;
|
||||
else
|
||||
a = ', *' + a;
|
||||
}
|
||||
let ret = 'error';
|
||||
if (b != '') {
|
||||
b.startsWith('[]') || b.startsWith('interface') || (b = '*' + b);
|
||||
ret = `(${b}, error)`;
|
||||
}
|
||||
let start = `${nm}(`;
|
||||
if (names) {
|
||||
start = start + 'ctx ';
|
||||
}
|
||||
return `${start}context.Context${a}) ${ret}`;
|
||||
}
|
||||
|
||||
const notNil = `if r.Params != nil {
|
||||
r.Reply(ctx, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInvalidParams, "Expected no params"))
|
||||
return true
|
||||
}`;
|
||||
// Go code for notifications. Side is client or server, m is the request method
|
||||
function goNot(side: side, m: string) {
|
||||
const n = not.get(m);
|
||||
let a = goType(side, m, n.typeArguments[0]);
|
||||
// let b = goType(m, n.typeArguments[1]); These are registration options
|
||||
const nm = methodName(m);
|
||||
side.methods.push(sig(nm, a, ''));
|
||||
const caseHdr = `case "${m}": // notif`;
|
||||
let case1 = notNil;
|
||||
if (a != '') {
|
||||
case1 = `var params ${a}
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, r, err)
|
||||
return true
|
||||
}
|
||||
if err := h.${side.name}.${nm}(ctx, ¶ms); err != nil {
|
||||
log.Error(ctx, "", err)
|
||||
}
|
||||
return true`;
|
||||
} else {
|
||||
case1 = `if err := h.${side.name}.${nm}(ctx); err != nil {
|
||||
log.Error(ctx, "", err)
|
||||
}
|
||||
return true`;
|
||||
}
|
||||
side.cases.push(`${caseHdr}\n${case1}`);
|
||||
|
||||
const arg3 = a == '' ? 'nil' : 'params';
|
||||
side.calls.push(`
|
||||
func (s *${side.name}Dispatcher) ${sig(nm, a, '', true)} {
|
||||
return s.Conn.Notify(ctx, "${m}", ${arg3})
|
||||
}`);
|
||||
}
|
||||
|
||||
// Go code for requests.
|
||||
function goReq(side: side, m: string) {
|
||||
const n = req.get(m);
|
||||
|
||||
const nm = methodName(m);
|
||||
let a = goType(side, m, n.typeArguments[0]);
|
||||
let b = goType(side, m, n.typeArguments[1]);
|
||||
if (n.getText().includes('Type0')) {
|
||||
b = a;
|
||||
a = ''; // workspace/workspaceFolders and shutdown
|
||||
}
|
||||
prb(`${side.name} req ${a != ''},${b != ''} ${nm} ${m} ${loc(n)}`)
|
||||
side.methods.push(sig(nm, a, b));
|
||||
|
||||
const caseHdr = `case "${m}": // req`;
|
||||
let case1 = notNil;
|
||||
if (a != '') {
|
||||
case1 = `var params ${a}
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, r, err)
|
||||
return true
|
||||
}`;
|
||||
}
|
||||
const arg2 = a == '' ? '' : ', ¶ms';
|
||||
let case2 = `if err := h.${side.name}.${nm}(ctx${arg2}); err != nil {
|
||||
log.Error(ctx, "", err)
|
||||
}`;
|
||||
if (b != '') {
|
||||
case2 = `resp, err := h.${side.name}.${nm}(ctx${arg2})
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
log.Error(ctx, "", err)
|
||||
}
|
||||
return true`;
|
||||
} else { // response is nil
|
||||
case2 = `err := h.${side.name}.${nm}(ctx${arg2})
|
||||
if err := r.Reply(ctx, nil, err); err != nil {
|
||||
log.Error(ctx, "", err)
|
||||
}
|
||||
return true`
|
||||
}
|
||||
|
||||
side.cases.push(`${caseHdr}\n${case1}\n${case2}`);
|
||||
|
||||
const callHdr = `func (s *${side.name}Dispatcher) ${sig(nm, a, b, true)} {`;
|
||||
let callBody = `return s.Conn.Call(ctx, "${m}", nil, nil)\n}`;
|
||||
if (b != '') {
|
||||
const p2 = a == '' ? 'nil' : 'params';
|
||||
let theRet = `result`;
|
||||
!b.startsWith('[]') && !b.startsWith('interface') && (theRet = '&result');
|
||||
callBody = `var result ${b}
|
||||
if err := s.Conn.Call(ctx, "${m}", ${
|
||||
p2}, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ${theRet}, nil
|
||||
}`;
|
||||
} else if (a != '') {
|
||||
callBody = `return s.Conn.Call(ctx, "${m}", params, nil) // Call, not Notify
|
||||
}`
|
||||
}
|
||||
side.calls.push(`${callHdr}\n${callBody}\n`);
|
||||
}
|
||||
|
||||
// make sure method names are unique
|
||||
let seenNames = new Set<string>();
|
||||
function methodName(m: string): string {
|
||||
const i = m.indexOf('/');
|
||||
let s = m.substring(i + 1);
|
||||
let x = s[0].toUpperCase() + s.substring(1);
|
||||
if (seenNames.has(x)) {
|
||||
x += m[0].toUpperCase() + m.substring(1, i);
|
||||
}
|
||||
seenNames.add(x);
|
||||
return x;
|
||||
}
|
||||
|
||||
function output(side: side) {
|
||||
if (side.outputFile === undefined) side.outputFile = `ts${side.name}.go`;
|
||||
side.fd = fs.openSync(side.outputFile, 'w');
|
||||
const f = function(s: string) {
|
||||
fs.writeSync(side.fd, s);
|
||||
fs.writeSync(side.fd, '\n');
|
||||
};
|
||||
f(`package protocol`);
|
||||
f(`// Code generated (see typescript/README.md) DO NOT EDIT.\n`);
|
||||
f(`
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"golang.org/x/tools/internal/jsonrpc2"
|
||||
"golang.org/x/tools/internal/telemetry/log"
|
||||
"golang.org/x/tools/internal/xcontext"
|
||||
)
|
||||
`);
|
||||
const a = side.name[0].toUpperCase() + side.name.substring(1)
|
||||
f(`type ${a} interface {`);
|
||||
side.methods.forEach((v) => {f(v)});
|
||||
f('}\n');
|
||||
f(`func (h ${
|
||||
side.name}Handler) Deliver(ctx context.Context, r *jsonrpc2.Request, delivered bool) bool {
|
||||
if delivered {
|
||||
return false
|
||||
}
|
||||
if ctx.Err() != nil {
|
||||
ctx := xcontext.Detach(ctx)
|
||||
r.Reply(ctx, nil, jsonrpc2.NewErrorf(RequestCancelledError, ""))
|
||||
return true
|
||||
}
|
||||
switch r.Method {`);
|
||||
side.cases.forEach((v) => {f(v)});
|
||||
f(`
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}`);
|
||||
f(`
|
||||
type ${side.name}Dispatcher struct {
|
||||
*jsonrpc2.Conn
|
||||
}
|
||||
`);
|
||||
side.calls.forEach((v) => {f(v)});
|
||||
if (side.name == 'server')
|
||||
f(`
|
||||
type CancelParams struct {
|
||||
/**
|
||||
* The request id to cancel.
|
||||
*/
|
||||
ID jsonrpc2.ID \`json:"id"\`
|
||||
}`);
|
||||
f(`// Types constructed to avoid structs as formal argument types`)
|
||||
side.ourTypes.forEach((val, key) => f(`type ${val} ${key}`));
|
||||
}
|
||||
|
||||
interface side {
|
||||
methods: string[];
|
||||
cases: string[];
|
||||
calls: string[];
|
||||
ourTypes: Map<string, string>;
|
||||
name: string; // client or server
|
||||
goName: string; // Client or Server
|
||||
outputFile?: string;
|
||||
fd?: number
|
||||
}
|
||||
let client: side = {
|
||||
methods: [],
|
||||
cases: [],
|
||||
calls: [],
|
||||
name: 'client',
|
||||
goName: 'Client',
|
||||
ourTypes: new Map<string, string>()
|
||||
};
|
||||
let server: side = {
|
||||
methods: [],
|
||||
cases: [],
|
||||
calls: [],
|
||||
name: 'server',
|
||||
goName: 'Server',
|
||||
ourTypes: new Map<string, string>()
|
||||
};
|
||||
|
||||
let req = new Map<string, ts.NewExpression>(); // requests
|
||||
let not = new Map<string, ts.NewExpression>(); // notifications
|
||||
let receives = new Map<string, 'server'|'client'>(); // who receives it
|
||||
|
||||
function setReceives() {
|
||||
// mark them all as server, then adjust the client ones.
|
||||
// it would be nice to have some independent check
|
||||
req.forEach((_, k) => {receives.set(k, 'server')});
|
||||
not.forEach((_, k) => {receives.set(k, 'server')});
|
||||
receives.set('window/logMessage', 'client');
|
||||
receives.set('telemetry/event', 'client');
|
||||
receives.set('client/registerCapability', 'client');
|
||||
receives.set('client/unregisterCapability', 'client');
|
||||
receives.set('window/showMessage', 'client');
|
||||
receives.set('window/showMessageRequest', 'client');
|
||||
receives.set('workspace/workspaceFolders', 'client');
|
||||
receives.set('workspace/configuration', 'client');
|
||||
receives.set('workspace/applyEdit', 'client');
|
||||
receives.set('textDocument/publishDiagnostics', 'client');
|
||||
// a small check
|
||||
receives.forEach((_, k) => {
|
||||
if (!req.get(k) && !not.get(k)) throw new Error(`missing ${k}}`);
|
||||
if (req.get(k) && not.get(k)) throw new Error(`dup ${k}`);
|
||||
})
|
||||
}
|
||||
|
||||
function goType(side: side, m: string, n: ts.Node): string {
|
||||
if (n === undefined) return '';
|
||||
if (ts.isTypeReferenceNode(n)) return n.typeName.getText();
|
||||
if (n.kind == ts.SyntaxKind.VoidKeyword) return '';
|
||||
if (n.kind == ts.SyntaxKind.AnyKeyword) return 'interface{}';
|
||||
if (ts.isArrayTypeNode(n)) return '[]' + goType(side, m, n.elementType);
|
||||
// special cases, before we get confused
|
||||
switch (m) {
|
||||
case 'textDocument/completion':
|
||||
return 'CompletionList';
|
||||
case 'textDocument/documentSymbol':
|
||||
return '[]DocumentSymbol';
|
||||
case 'textDocument/prepareRename':
|
||||
return 'Range';
|
||||
case 'textDocument/codeAction':
|
||||
return '[]CodeAction';
|
||||
}
|
||||
if (ts.isUnionTypeNode(n)) {
|
||||
let x: string[] = [];
|
||||
n.types.forEach(
|
||||
(v) => {v.kind != ts.SyntaxKind.NullKeyword &&
|
||||
x.push(goType(side, m, v))});
|
||||
if (x.length == 1) return x[0];
|
||||
|
||||
prb(`===========${m} ${x}`)
|
||||
// Because we don't fully resolve types, we don't know that
|
||||
// Definition is Location | Location[]
|
||||
if (x[0] == 'Definition') return '[]Location';
|
||||
if (x[1] == '[]' + x[0] + 'Link') return x[1];
|
||||
throw new Error(`${m}, ${x} unexpected types`)
|
||||
}
|
||||
if (ts.isIntersectionTypeNode(n)) {
|
||||
// we expect only TypeReferences, and put out a struct with embedded types
|
||||
// This is not good, as it uses a struct where a type name ought to be.
|
||||
let x: string[] = [];
|
||||
n.types.forEach((v) => {
|
||||
// expect only TypeReferences
|
||||
if (!ts.isTypeReferenceNode(v)) {
|
||||
throw new Error(
|
||||
`expected only TypeReferences in Intersection ${getText(n)}`)
|
||||
}
|
||||
x.push(goType(side, m, v));
|
||||
x.push(';')
|
||||
})
|
||||
x.push('}')
|
||||
let ans = 'struct {'.concat(...x);
|
||||
// If ans does not have a type, create it
|
||||
if (side.ourTypes.get(ans) == undefined) {
|
||||
side.ourTypes.set(ans, 'Param' + getText(n).substring(0, 6))
|
||||
}
|
||||
// Return the type
|
||||
return side.ourTypes.get(ans)
|
||||
}
|
||||
return '?';
|
||||
}
|
||||
|
||||
// walk the AST finding Requests and Notifications
|
||||
function genStuff(node: ts.Node) {
|
||||
if (!ts.isNewExpression(node)) {
|
||||
ts.forEachChild(node, genStuff)
|
||||
return;
|
||||
}
|
||||
// process the right kind of new expression
|
||||
const wh = node.expression.getText();
|
||||
if (wh != 'RequestType' && wh != 'RequestType0' && wh != 'NotificationType' &&
|
||||
wh != 'NotificationType0')
|
||||
return;
|
||||
if (node.arguments === undefined || node.arguments.length != 1 ||
|
||||
!ts.isStringLiteral(node.arguments[0])) {
|
||||
throw new Error(`missing n.arguments ${loc(node)}`)
|
||||
}
|
||||
// RequestType<useful>=new RequestTYpe('foo')
|
||||
if (node.typeArguments === undefined) {
|
||||
node.typeArguments = lookUp(node);
|
||||
}
|
||||
// new RequestType<useful>
|
||||
let s = node.arguments[0].getText();
|
||||
// Request or Notification
|
||||
const v = wh[0] == 'R' ? req : not;
|
||||
s = s.substring(1, s.length - 1); // remove quoting
|
||||
if (s == '$/cancelRequest') return; // special case in output
|
||||
v.set(s, node);
|
||||
}
|
||||
|
||||
// find the text of a node
|
||||
function getText(node: ts.Node): string {
|
||||
let sf = node.getSourceFile();
|
||||
let start = node.getStart(sf)
|
||||
let end = node.getEnd()
|
||||
return sf.text.substring(start, end)
|
||||
}
|
||||
|
||||
function lookUp(n: ts.NewExpression): ts.NodeArray<ts.TypeNode> {
|
||||
// parent should be VariableDeclaration. its children should be
|
||||
// Identifier('type') ???
|
||||
// TypeReference: [Identifier('RequestType1), ]
|
||||
// NewExpression (us)
|
||||
const p = n.parent;
|
||||
if (!ts.isVariableDeclaration(p)) throw new Error(`not variable decl`);
|
||||
const tr = p.type;
|
||||
if (!ts.isTypeReferenceNode(tr)) throw new Error(`not TypeReference`);
|
||||
return tr.typeArguments;
|
||||
}
|
||||
|
||||
function dumpAST() {
|
||||
// dump the ast, for debugging
|
||||
for (const sourceFile of program.getSourceFiles()) {
|
||||
if (!sourceFile.isDeclarationFile) {
|
||||
// walk the tree to do stuff
|
||||
ts.forEachChild(sourceFile, describe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// some tokens have the wrong default name
|
||||
function strKind(n: ts.Node): string {
|
||||
const x = ts.SyntaxKind[n.kind];
|
||||
switch (x) {
|
||||
default:
|
||||
return x;
|
||||
case 'FirstAssignment':
|
||||
return 'EqualsToken';
|
||||
case 'FirstBinaryOperator':
|
||||
return 'LessThanToken';
|
||||
case 'FirstCompoundAssignment':
|
||||
return 'PlusEqualsToken';
|
||||
case 'FirstContextualKeyword':
|
||||
return 'AbstractKeyword';
|
||||
case 'FirstLiteralToken':
|
||||
return 'NumericLiteral';
|
||||
case 'FirstNode':
|
||||
return 'QualifiedName';
|
||||
case 'FirstTemplateToken':
|
||||
return 'NoSubstitutionTemplateLiteral';
|
||||
case 'LastTemplateToken':
|
||||
return 'TemplateTail';
|
||||
case 'FirstTypeNode':
|
||||
return 'TypePredicate';
|
||||
}
|
||||
}
|
||||
|
||||
function describe(node: ts.Node) {
|
||||
if (node === undefined) {
|
||||
return
|
||||
}
|
||||
let indent = '';
|
||||
|
||||
function f(n: ts.Node) {
|
||||
if (ts.isIdentifier(n)) {
|
||||
pra(`${indent} ${loc(n)} ${strKind(n)} ${n.text} \n`)
|
||||
} else if (ts.isPropertySignature(n) || ts.isEnumMember(n)) {
|
||||
pra(`${indent} ${loc(n)} ${strKind(n)} \n`)
|
||||
} else if (ts.isTypeLiteralNode(n)) {
|
||||
let m = n.members
|
||||
pra(`${indent} ${loc(n)} ${strKind(n)} ${m.length} \n`)
|
||||
} else {
|
||||
pra(`${indent} ${loc(n)} ${strKind(n)} \n`)
|
||||
};
|
||||
indent += ' '
|
||||
ts.forEachChild(n, f)
|
||||
indent = indent.slice(0, indent.length - 2)
|
||||
}
|
||||
f(node)
|
||||
}
|
||||
|
||||
// string version of the location in the source file
|
||||
function loc(node: ts.Node): string {
|
||||
const sf = node.getSourceFile();
|
||||
const start = node.getStart()
|
||||
const x = sf.getLineAndCharacterOfPosition(start)
|
||||
const full = node.getFullStart()
|
||||
const y = sf.getLineAndCharacterOfPosition(full)
|
||||
let fn = sf.fileName
|
||||
const n = fn.search(/-node./)
|
||||
fn = fn.substring(n + 6)
|
||||
return `${fn} ${x.line + 1}: ${x.character + 1} (${y.line + 1}: ${
|
||||
y.character + 1})`
|
||||
}
|
||||
|
||||
// ad hoc argument parsing: [-d dir] [-o outputfile], and order matters
|
||||
function main() {
|
||||
let args = process.argv.slice(2) // effective command line
|
||||
if (args.length > 0) {
|
||||
let j = 0;
|
||||
if (args[j] == '-d') {
|
||||
dir = args[j + 1]
|
||||
j += 2
|
||||
}
|
||||
if (j != args.length) throw new Error(`incomprehensible args ${args}`)
|
||||
}
|
||||
let files: string[] = [];
|
||||
for (let i = 0; i < fnames.length; i++) {
|
||||
files.push(`${dir}${fnames[i]}`)
|
||||
}
|
||||
createOutputFiles()
|
||||
generate(
|
||||
files, {target: ts.ScriptTarget.ES5, module: ts.ModuleKind.CommonJS});
|
||||
}
|
||||
|
||||
main()
|
@ -10,10 +10,11 @@ import * as ts from 'typescript';
|
||||
let dir = process.env['HOME'];
|
||||
const srcDir = '/vscode-languageserver-node'
|
||||
export const fnames = [
|
||||
`${dir}${srcDir}/protocol/src/protocol.ts`,
|
||||
//`${dir}${srcDir}/protocol/src/protocol.ts`, // why isn't this main.ts?
|
||||
`${dir}/${srcDir}/protocol/src/main.ts`,
|
||||
`${dir}${srcDir}/types/src/main.ts`, `${dir}${srcDir}/jsonrpc/src/main.ts`
|
||||
];
|
||||
export const gitHash = '635ab1fe6f8c57ce9402e573d007f24d6d290fd3';
|
||||
export const gitHash = '7b90c29d0cb5cd7b9c41084f6cb3781a955adeba';
|
||||
let outFname = 'tsprotocol.go';
|
||||
let fda: number, fdb: number, fde: number; // file descriptors
|
||||
|
||||
@ -65,10 +66,10 @@ export function computeHeader(pkgDoc: boolean): string {
|
||||
}
|
||||
}
|
||||
const a =
|
||||
`// Package protocol contains data types and code for LSP jsonrpcs\n` +
|
||||
`// generated automatically from vscode-languageserver-node\n` +
|
||||
`// commit: ${gitHash}\n` +
|
||||
`// last fetched ${lastDate}\n`
|
||||
`// Package protocol contains data types and code for LSP jsonrpcs\n` +
|
||||
`// generated automatically from vscode-languageserver-node\n` +
|
||||
`// commit: ${gitHash}\n` +
|
||||
`// last fetched ${lastDate}\n`
|
||||
const b = 'package protocol\n'
|
||||
const c = `\n// Code generated (see typescript/README.md) DO NOT EDIT.\n\n`
|
||||
if (pkgDoc) {
|
||||
@ -85,7 +86,7 @@ export function goName(s: string): string {
|
||||
if (s.charAt(0) == '_') {
|
||||
ans = 'Inner' + s.substring(1)
|
||||
}
|
||||
else {ans = s.substring(0, 1).toUpperCase() + s.substring(1)};
|
||||
else { ans = s.substring(0, 1).toUpperCase() + s.substring(1) };
|
||||
ans = ans.replace(/Uri$/, 'URI')
|
||||
ans = ans.replace(/Id$/, 'ID')
|
||||
return ans
|
||||
@ -94,7 +95,7 @@ export function goName(s: string): string {
|
||||
// Generate JSON tag for a struct field
|
||||
export function JSON(n: ts.PropertySignature): string {
|
||||
const json = `\`json:"${n.name.getText()}${
|
||||
n.questionToken != undefined ? ',omitempty' : ''}"\``;
|
||||
n.questionToken != undefined ? ',omitempty' : ''}"\``;
|
||||
return json
|
||||
}
|
||||
|
||||
@ -107,12 +108,13 @@ export function constName(nm: string, type: string): string {
|
||||
['SignatureHelpTriggerKind', 'Sig'], ['CompletionItemTag', 'Compl']
|
||||
]) // typeName->prefix
|
||||
let suff = new Map<string, string>([
|
||||
['CompletionItemKind', 'Completion'], ['InsertTextFormat', 'TextFormat']
|
||||
['CompletionItemKind', 'Completion'], ['InsertTextFormat', 'TextFormat'],
|
||||
['SymbolTag', 'Symbol']
|
||||
])
|
||||
let ans = nm;
|
||||
if (pref.get(type)) ans = pref.get(type) + ans;
|
||||
if (suff.has(type)) ans = ans + suff.get(type)
|
||||
return ans
|
||||
return ans
|
||||
}
|
||||
|
||||
// Find the comments associated with an AST node
|
||||
@ -129,7 +131,7 @@ export function getComments(node: ts.Node): string {
|
||||
|
||||
export function printAST(program: ts.Program) {
|
||||
// dump the ast, for debugging
|
||||
const f = function(n: ts.Node) {
|
||||
const f = function (n: ts.Node) {
|
||||
describe(n, pra)
|
||||
};
|
||||
for (const sourceFile of program.getSourceFiles()) {
|
||||
@ -171,7 +173,7 @@ function describe(node: ts.Node, pr: (s: string) => any) {
|
||||
else if (ts.isStringLiteral(n)) {
|
||||
pr(`${indent} ${loc(n)} ${strKind(n)} ${n.text} \n`)
|
||||
}
|
||||
else {pr(`${indent} ${loc(n)} ${strKind(n)} \n`)};
|
||||
else { pr(`${indent} ${loc(n)} ${strKind(n)} \n`) };
|
||||
indent += ' .'
|
||||
ts.forEachChild(n, f)
|
||||
indent = indent.slice(0, indent.length - 2)
|
||||
@ -191,7 +193,7 @@ export function loc(node: ts.Node): string {
|
||||
const n = fn.search(/-node./)
|
||||
fn = fn.substring(n + 6)
|
||||
return `${fn} ${x.line + 1}: ${x.character + 1} (${y.line + 1}: ${
|
||||
y.character + 1})`
|
||||
y.character + 1})`
|
||||
}
|
||||
// --- various string stuff
|
||||
|
||||
@ -199,7 +201,7 @@ export function loc(node: ts.Node): string {
|
||||
// as part of printing the AST tree
|
||||
function kinds(n: ts.Node): string {
|
||||
let res = 'Seen ' + strKind(n);
|
||||
function f(n: ts.Node): void{res += ' ' + strKind(n)};
|
||||
function f(n: ts.Node): void { res += ' ' + strKind(n) };
|
||||
ts.forEachChild(n, f)
|
||||
return res
|
||||
}
|
||||
|
@ -100,6 +100,10 @@ func (s *Server) Implementation(ctx context.Context, params *protocol.Implementa
|
||||
return s.implementation(ctx, params)
|
||||
}
|
||||
|
||||
func (s *Server) IncomingCalls(context.Context, *protocol.CallHierarchyIncomingCallsParams) ([]protocol.CallHierarchyIncomingCall, error) {
|
||||
return nil, notImplemented("IncomingCalls")
|
||||
}
|
||||
|
||||
func (s *Server) Initialize(ctx context.Context, params *protocol.ParamInitialize) (*protocol.InitializeResult, error) {
|
||||
return s.initialize(ctx, params)
|
||||
}
|
||||
@ -120,6 +124,14 @@ func (s *Server) OnTypeFormatting(context.Context, *protocol.DocumentOnTypeForma
|
||||
return nil, notImplemented("OnTypeFormatting")
|
||||
}
|
||||
|
||||
func (s *Server) OutgoingCalls(context.Context, *protocol.CallHierarchyOutgoingCallsParams) ([]protocol.CallHierarchyOutgoingCall, error) {
|
||||
return nil, notImplemented("OutgoingCalls")
|
||||
}
|
||||
|
||||
func (s *Server) PrepareCallHierarchy(context.Context, *protocol.CallHierarchyPrepareParams) ([]protocol.CallHierarchyItem, error) {
|
||||
return nil, notImplemented("PrepareCallHierarchy")
|
||||
}
|
||||
|
||||
func (s *Server) PrepareRename(ctx context.Context, params *protocol.PrepareRenameParams) (interface{}, error) {
|
||||
return s.prepareRename(ctx, params)
|
||||
}
|
||||
@ -156,6 +168,18 @@ func (s *Server) SelectionRange(context.Context, *protocol.SelectionRangeParams)
|
||||
return nil, notImplemented("SelectionRange")
|
||||
}
|
||||
|
||||
func (s *Server) SemanticTokens(context.Context, *protocol.SemanticTokensParams) (*protocol.SemanticTokens, error) {
|
||||
return nil, notImplemented("SemanticTokens")
|
||||
}
|
||||
|
||||
func (s *Server) SemanticTokensEdits(context.Context, *protocol.SemanticTokensEditsParams) (interface{}, error) {
|
||||
return nil, notImplemented("SemanticTokensEdits")
|
||||
}
|
||||
|
||||
func (s *Server) SemanticTokensRange(context.Context, *protocol.SemanticTokensRangeParams) (*protocol.SemanticTokens, error) {
|
||||
return nil, notImplemented("SemanticTokensRange")
|
||||
}
|
||||
|
||||
func (s *Server) SetTraceNotification(context.Context, *protocol.SetTraceParams) error {
|
||||
return notImplemented("SetTraceNotification")
|
||||
}
|
||||
@ -183,3 +207,11 @@ func (s *Server) WillSave(context.Context, *protocol.WillSaveTextDocumentParams)
|
||||
func (s *Server) WillSaveWaitUntil(context.Context, *protocol.WillSaveTextDocumentParams) ([]protocol.TextEdit, error) {
|
||||
return nil, notImplemented("WillSaveWaitUntil")
|
||||
}
|
||||
|
||||
func (s *Server) WorkDoneProgressCancel(context.Context, *protocol.WorkDoneProgressCancelParams) error {
|
||||
return notImplemented("WorkDoneProgressCancel")
|
||||
}
|
||||
|
||||
func (s *Server) WorkDoneProgressCreate(context.Context, *protocol.WorkDoneProgressCreateParams) error {
|
||||
return notImplemented("WorkDoneProgressCreate")
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user