Skip to content

Commit 416e888

Browse files
committed
Merge branch 'main' into multiProjectImpl
2 parents 61388d6 + f16a4b7 commit 416e888

File tree

13 files changed

+301
-144
lines changed

13 files changed

+301
-144
lines changed

_extension/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"url": "https://github.com/microsoft/typescript-go"
1414
},
1515
"engines": {
16-
"vscode": "^1.100.0"
16+
"vscode": "^1.106.0"
1717
},
1818
"capabilities": {
1919
"untrustedWorkspaces": {
@@ -119,10 +119,10 @@
119119
"bundle": "esbuild src/extension.ts --bundle --external:vscode --platform=node --format=cjs --outfile=dist/extension.bundle.js --minify"
120120
},
121121
"dependencies": {
122-
"vscode-languageclient": "^9.0.1"
122+
"vscode-languageclient": "^10.0.0-next.18"
123123
},
124124
"devDependencies": {
125-
"@types/vscode": "^1.100.0",
125+
"@types/vscode": "^1.106.0",
126126
"@vscode/vsce": "^3.7.0",
127127
"esbuild": "^0.27.0"
128128
}

_extension/src/client.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,14 @@ import { getLanguageForUri } from "./util";
2020
const codeLensShowLocationsCommandName = "typescript.native-preview.codeLens.showLocations";
2121

2222
export class Client {
23-
private outputChannel: vscode.OutputChannel;
24-
private traceOutputChannel: vscode.OutputChannel;
23+
private outputChannel: vscode.LogOutputChannel;
24+
private traceOutputChannel: vscode.LogOutputChannel;
2525
private clientOptions: LanguageClientOptions;
2626
private client?: LanguageClient;
2727
private exe: ExeInfo | undefined;
2828
private onStartedCallbacks: Set<() => void> = new Set();
2929

30-
constructor(outputChannel: vscode.OutputChannel, traceOutputChannel: vscode.OutputChannel) {
30+
constructor(outputChannel: vscode.LogOutputChannel, traceOutputChannel: vscode.LogOutputChannel) {
3131
this.outputChannel = outputChannel;
3232
this.traceOutputChannel = traceOutputChannel;
3333
this.clientOptions = {
@@ -128,6 +128,10 @@ export class Client {
128128
vscode.commands.executeCommand("setContext", "typescript.native-preview.serverRunning", true);
129129
this.onStartedCallbacks.forEach(callback => callback());
130130

131+
if (this.traceOutputChannel.logLevel !== vscode.LogLevel.Trace) {
132+
this.traceOutputChannel.appendLine(`To see LSP trace output, set this output's log level to "Trace" (gear icon next to the dropdown).`);
133+
}
134+
131135
const codeLensLocationsCommand = vscode.commands.registerCommand(codeLensShowLocationsCommandName, (...args: unknown[]) => {
132136
if (args.length !== 3) {
133137
throw new Error("Unexpected number of arguments.");

_extension/src/extension.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ import { setupVersionStatusItem } from "./versionStatusItem";
1212
export async function activate(context: vscode.ExtensionContext) {
1313
await vscode.commands.executeCommand("setContext", "typescript.native-preview.serverRunning", false);
1414
registerEnablementCommands(context);
15-
const output = vscode.window.createOutputChannel("typescript-native-preview", "log");
16-
const traceOutput = vscode.window.createOutputChannel("typescript-native-preview (LSP)");
15+
const output = vscode.window.createOutputChannel("typescript-native-preview", { log: true });
16+
const traceOutput = vscode.window.createOutputChannel("typescript-native-preview (LSP)", { log: true });
1717
context.subscriptions.push(output, traceOutput);
1818

1919
let disposeLanguageFeatures: vscode.Disposable | undefined;
@@ -77,7 +77,7 @@ export async function activate(context: vscode.ExtensionContext) {
7777
context.subscriptions.push(disposeLanguageFeatures);
7878
}
7979

80-
async function activateLanguageFeatures(context: vscode.ExtensionContext, output: vscode.OutputChannel, traceOutput: vscode.OutputChannel): Promise<vscode.Disposable> {
80+
async function activateLanguageFeatures(context: vscode.ExtensionContext, output: vscode.LogOutputChannel, traceOutput: vscode.LogOutputChannel): Promise<vscode.Disposable> {
8181
const disposables: vscode.Disposable[] = [];
8282

8383
const client = new Client(output, traceOutput);

internal/lsp/logger.go

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
package lsp
2+
3+
import (
4+
"fmt"
5+
"sync"
6+
7+
"github.com/microsoft/typescript-go/internal/lsp/lsproto"
8+
"github.com/microsoft/typescript-go/internal/project/logging"
9+
)
10+
11+
var _ logging.Logger = (*logger)(nil)
12+
13+
type logger struct {
14+
server *Server
15+
mu sync.Mutex
16+
verbose bool
17+
}
18+
19+
func newLogger(server *Server) *logger {
20+
return &logger{
21+
server: server,
22+
}
23+
}
24+
25+
func (l *logger) sendLogMessage(msgType lsproto.MessageType, message string) {
26+
if l == nil {
27+
return
28+
}
29+
30+
if !l.server.initStarted.Load() {
31+
fmt.Fprintln(l.server.stderr, message)
32+
return
33+
}
34+
35+
notification := lsproto.WindowLogMessageInfo.NewNotificationMessage(&lsproto.LogMessageParams{
36+
Type: msgType,
37+
Message: message,
38+
})
39+
l.server.outgoingQueue <- notification.Message()
40+
}
41+
42+
func (l *logger) Log(msg ...any) {
43+
if l == nil {
44+
return
45+
}
46+
l.sendLogMessage(lsproto.MessageTypeLog, fmt.Sprint(msg...))
47+
}
48+
49+
func (l *logger) Logf(format string, args ...any) {
50+
if l == nil {
51+
return
52+
}
53+
l.sendLogMessage(lsproto.MessageTypeLog, fmt.Sprintf(format, args...))
54+
}
55+
56+
func (l *logger) Verbose() logging.Logger {
57+
if l == nil {
58+
return nil
59+
}
60+
l.mu.Lock()
61+
defer l.mu.Unlock()
62+
if !l.verbose {
63+
return nil
64+
}
65+
return l
66+
}
67+
68+
func (l *logger) IsVerbose() bool {
69+
if l == nil {
70+
return false
71+
}
72+
l.mu.Lock()
73+
defer l.mu.Unlock()
74+
return l.verbose
75+
}
76+
77+
func (l *logger) SetVerbose(verbose bool) {
78+
if l == nil {
79+
return
80+
}
81+
l.mu.Lock()
82+
defer l.mu.Unlock()
83+
l.verbose = verbose
84+
}
85+
86+
func (l *logger) Error(msg ...any) {
87+
if l == nil {
88+
return
89+
}
90+
l.sendLogMessage(lsproto.MessageTypeError, fmt.Sprint(msg...))
91+
}
92+
93+
func (l *logger) Errorf(format string, args ...any) {
94+
if l == nil {
95+
return
96+
}
97+
l.sendLogMessage(lsproto.MessageTypeError, fmt.Sprintf(format, args...))
98+
}
99+
100+
func (l *logger) Warn(msg ...any) {
101+
if l == nil {
102+
return
103+
}
104+
l.sendLogMessage(lsproto.MessageTypeWarning, fmt.Sprint(msg...))
105+
}
106+
107+
func (l *logger) Warnf(format string, args ...any) {
108+
if l == nil {
109+
return
110+
}
111+
l.sendLogMessage(lsproto.MessageTypeWarning, fmt.Sprintf(format, args...))
112+
}
113+
114+
func (l *logger) Info(msg ...any) {
115+
if l == nil {
116+
return
117+
}
118+
l.sendLogMessage(lsproto.MessageTypeInfo, fmt.Sprint(msg...))
119+
}
120+
121+
func (l *logger) Infof(format string, args ...any) {
122+
if l == nil {
123+
return
124+
}
125+
l.sendLogMessage(lsproto.MessageTypeInfo, fmt.Sprintf(format, args...))
126+
}

internal/lsp/lsproto/_generate/fetchModel.mts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const __dirname = path.dirname(__filename);
88
const metaModelPath = path.join(__dirname, "metaModel.json");
99
const metaModelSchemaPath = path.join(__dirname, "metaModelSchema.mts");
1010

11-
const hash = "dadd73f7fc283b4d0adb602adadcf4be16ef3a7b";
11+
const hash = "2abd2d977aa36e8c6b242ff048bdbf5df71e3088";
1212

1313
const metaModelURL = `https://raw.githubusercontent.com/microsoft/vscode-languageserver-node/${hash}/protocol/metaModel.json`;
1414
const metaModelSchemaURL = `https://raw.githubusercontent.com/microsoft/vscode-languageserver-node/${hash}/tools/src/metaModel.ts`;

internal/lsp/lsproto/_generate/metaModelSchema.mts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,16 @@ export type Request = {
202202
* the property contains the deprecation message.
203203
*/
204204
deprecated?: string;
205+
206+
/**
207+
* The client capability property path if any.
208+
*/
209+
clientCapability?: string;
210+
211+
/**
212+
* The server capability property path if any.
213+
*/
214+
serverCapability?: string;
205215
};
206216

207217
/**
@@ -269,6 +279,16 @@ export type Notification = {
269279
* the property contains the deprecation message.
270280
*/
271281
deprecated?: string;
282+
283+
/**
284+
* The client capability property path if any.
285+
*/
286+
clientCapability?: string;
287+
288+
/**
289+
* The server capability property path if any.
290+
*/
291+
serverCapability?: string;
272292
};
273293

274294
/**

internal/lsp/server.go

Lines changed: 17 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import (
2323
"github.com/microsoft/typescript-go/internal/lsp/lsproto"
2424
"github.com/microsoft/typescript-go/internal/project"
2525
"github.com/microsoft/typescript-go/internal/project/ata"
26-
"github.com/microsoft/typescript-go/internal/project/logging"
2726
"github.com/microsoft/typescript-go/internal/tspath"
2827
"github.com/microsoft/typescript-go/internal/vfs"
2928
"golang.org/x/sync/errgroup"
@@ -40,27 +39,17 @@ type ServerOptions struct {
4039
TypingsLocation string
4140
ParseCache *project.ParseCache
4241
NpmInstall func(cwd string, args []string) ([]byte, error)
43-
44-
// Test options
45-
Client project.Client
46-
Logger logging.Logger
4742
}
4843

4944
func NewServer(opts *ServerOptions) *Server {
5045
if opts.Cwd == "" {
5146
panic("Cwd is required")
5247
}
53-
var logger logging.Logger
54-
if opts.Logger != nil {
55-
logger = opts.Logger
56-
} else {
57-
logger = logging.NewLogger(opts.Err)
58-
}
59-
return &Server{
48+
49+
s := &Server{
6050
r: opts.In,
6151
w: opts.Out,
6252
stderr: opts.Err,
63-
logger: logger,
6453
requestQueue: make(chan *lsproto.RequestMessage, 100),
6554
outgoingQueue: make(chan *lsproto.Message, 100),
6655
pendingClientRequests: make(map[lsproto.ID]pendingClientRequest),
@@ -71,9 +60,11 @@ func NewServer(opts *ServerOptions) *Server {
7160
typingsLocation: opts.TypingsLocation,
7261
parseCache: opts.ParseCache,
7362
npmInstall: opts.NpmInstall,
74-
client: opts.Client,
7563
initComplete: make(chan struct{}),
7664
}
65+
s.logger = newLogger(s)
66+
67+
return s
7768
}
7869

7970
var (
@@ -143,7 +134,8 @@ type Server struct {
143134

144135
stderr io.Writer
145136

146-
logger logging.Logger
137+
logger *logger
138+
initStarted atomic.Bool
147139
clientSeq atomic.Int32
148140
requestQueue chan *lsproto.RequestMessage
149141
outgoingQueue chan *lsproto.Message
@@ -293,7 +285,7 @@ func (s *Server) RequestConfiguration(ctx context.Context) (*lsutil.UserPreferen
293285
if err != nil {
294286
return nil, fmt.Errorf("configure request failed: %w", err)
295287
}
296-
s.Log(fmt.Sprintf("\n\nconfiguration: %+v, %T\n\n", configs, configs))
288+
s.logger.Infof("configuration: %+v, %T", configs, configs)
297289
userPreferences := s.session.NewUserPreferences()
298290
for _, item := range configs {
299291
if parsed := userPreferences.Parse(item); parsed != nil {
@@ -508,7 +500,7 @@ func (s *Server) handleRequestOrNotification(ctx context.Context, req *lsproto.R
508500
if handler := handlers()[req.Method]; handler != nil {
509501
return handler(s, ctx, req)
510502
}
511-
s.Log("unknown method", req.Method)
503+
s.logger.Warn("unknown method", req.Method)
512504
if req.ID != nil {
513505
s.sendError(req.ID, lsproto.ErrorCodeInvalidRequest)
514506
}
@@ -701,11 +693,11 @@ func (c *crossProjectOrchestrator) RecoverWith(r any) {
701693

702694
func (s *Server) recoverWith(req *lsproto.RequestMessage, r any) {
703695
stack := debug.Stack()
704-
s.Log("panic handling request", req.Method, r, string(stack))
696+
s.logger.Error("panic handling request", req.Method, r, string(stack))
705697
if req.ID != nil {
706698
s.sendError(req.ID, fmt.Errorf("%w: panic handling request %s: %v", lsproto.ErrorCodeInternalError, req.Method, r))
707699
} else {
708-
s.Log("unhandled panic in notification", req.Method, r)
700+
s.logger.Error("unhandled panic in notification", req.Method, r)
709701
}
710702
}
711703

@@ -720,15 +712,16 @@ func (s *Server) handleInitialize(ctx context.Context, params *lsproto.Initializ
720712
return nil, lsproto.ErrorCodeInvalidRequest
721713
}
722714

715+
s.initStarted.Store(true)
716+
723717
s.initializeParams = params
724-
s.clientCapabilities = resolveClientCapabilities(params.Capabilities)
718+
s.clientCapabilities = lsproto.ResolveClientCapabilities(params.Capabilities)
725719

726-
if _, err := fmt.Fprint(s.stderr, "Resolved client capabilities: "); err != nil {
727-
return nil, err
728-
}
729-
if err := jsonutil.MarshalIndentWrite(s.stderr, &s.clientCapabilities, "", "\t"); err != nil {
720+
capabilitiesJSON, err := jsonutil.MarshalIndent(&s.clientCapabilities, "", "\t")
721+
if err != nil {
730722
return nil, err
731723
}
724+
s.logger.Info("Resolved client capabilities: " + string(capabilitiesJSON))
732725

733726
s.positionEncoding = lsproto.PositionEncodingKindUTF16
734727
if slices.Contains(s.clientCapabilities.General.PositionEncodings, lsproto.PositionEncodingKindUTF8) {
@@ -1160,10 +1153,6 @@ func (s *Server) handleCallHierarchyOutgoingCalls(
11601153
return languageService.ProvideCallHierarchyOutgoingCalls(ctx, params.Item)
11611154
}
11621155

1163-
func (s *Server) Log(msg ...any) {
1164-
fmt.Fprintln(s.stderr, msg...)
1165-
}
1166-
11671156
// !!! temporary; remove when we have `handleDidChangeConfiguration`/implicit project config support
11681157
func (s *Server) SetCompilerOptionsForInferredProjects(ctx context.Context, options *core.CompilerOptions) {
11691158
s.compilerOptionsForInferredProjects = options
@@ -1196,29 +1185,3 @@ func isBlockingMethod(method lsproto.Method) bool {
11961185
func ptrTo[T any](v T) *T {
11971186
return &v
11981187
}
1199-
1200-
func resolveClientCapabilities(caps *lsproto.ClientCapabilities) lsproto.ResolvedClientCapabilities {
1201-
resolved := lsproto.ResolveClientCapabilities(caps)
1202-
1203-
// Some clients claim that push and pull diagnostics have different capabilities,
1204-
// including vscode-languageclient v9. Work around this by defaulting any missing
1205-
// pull diagnostic caps with the pull diagnostic equivalents.
1206-
//
1207-
// TODO: remove when we upgrade to vscode-languageclient v10, which fixes this issue.
1208-
publish := resolved.TextDocument.PublishDiagnostics
1209-
diagnostic := &resolved.TextDocument.Diagnostic
1210-
if !diagnostic.RelatedInformation && publish.RelatedInformation {
1211-
diagnostic.RelatedInformation = true
1212-
}
1213-
if !diagnostic.CodeDescriptionSupport && publish.CodeDescriptionSupport {
1214-
diagnostic.CodeDescriptionSupport = true
1215-
}
1216-
if !diagnostic.DataSupport && publish.DataSupport {
1217-
diagnostic.DataSupport = true
1218-
}
1219-
if len(diagnostic.TagSupport.ValueSet) == 0 && len(publish.TagSupport.ValueSet) > 0 {
1220-
diagnostic.TagSupport.ValueSet = publish.TagSupport.ValueSet
1221-
}
1222-
1223-
return resolved
1224-
}

0 commit comments

Comments
 (0)