diff --git a/_extension/package.json b/_extension/package.json index b218b3496a..0635664c30 100644 --- a/_extension/package.json +++ b/_extension/package.json @@ -31,6 +31,11 @@ { "title": "TypeScript Native Preview", "properties": { + "typescript.native-preview.customConfigFileName": { + "type": "string", + "description": "Custom config file name to use, before defaulting to tsconfig.json/jsconfig.json.", + "tags": ["experimental"] + }, "typescript.native-preview.trace.server": { "type": "string", "enum": [ diff --git a/_extension/src/client.ts b/_extension/src/client.ts index b759501e97..05c78c18c7 100644 --- a/_extension/src/client.ts +++ b/_extension/src/client.ts @@ -90,10 +90,11 @@ export class Client { this.exe = exe; this.outputChannel.appendLine(`Resolved to ${this.exe.path}`); - // Get pprofDir + // Get pprofDir const config = vscode.workspace.getConfiguration("typescript.native-preview"); const pprofDir = config.get("pprofDir"); const pprofArgs = pprofDir ? ["--pprofDir", pprofDir] : []; + const customConfigFileName = config.get("customConfigFileName") ?? ""; const serverOptions: ServerOptions = { run: { @@ -108,12 +109,17 @@ export class Client { }, }; - this.client = new LanguageClient( - "typescript.native-preview", - "typescript.native-preview-lsp", - serverOptions, - this.clientOptions, - ); + this.client = new LanguageClient( + "typescript.native-preview", + "typescript.native-preview-lsp", + serverOptions, + { + ...this.clientOptions, + initializationOptions: { + customConfigFileName, + }, + }, + ); this.outputChannel.appendLine(`Starting language server...`); await this.client.start(); diff --git a/_extension/src/extension.ts b/_extension/src/extension.ts index d1fe6036eb..675ca87b21 100644 --- a/_extension/src/extension.ts +++ b/_extension/src/extension.ts @@ -42,6 +42,15 @@ export async function activate(context: vscode.ExtensionContext) { } } } + if (event.affectsConfiguration("typescript.native-preview.customConfigFileName")) { + // Show prompt to restart to pick up the new initialization options + setTimeout(async () => { + const selected = await vscode.window.showInformationMessage("TypeScript Native Preview settings have changed. Restart extensions to apply changes.", "Restart Extensions"); + if (selected) { + vscode.commands.executeCommand("workbench.action.restartExtensionHost"); + } + }, 100); + } })); const useTsgo = vscode.workspace.getConfiguration("typescript").get("experimental.useTsgo"); diff --git a/_submodules/TypeScript b/_submodules/TypeScript index 9e8eaa1746..add6971195 160000 --- a/_submodules/TypeScript +++ b/_submodules/TypeScript @@ -1 +1 @@ -Subproject commit 9e8eaa1746b0d09c3cd29048126ef9cf24f29c03 +Subproject commit add697119549734b24d46b30b9f6d2e757c6d53a diff --git a/internal/lsp/server.go b/internal/lsp/server.go index cecd426747..6a67622fc4 100644 --- a/internal/lsp/server.go +++ b/internal/lsp/server.go @@ -701,15 +701,26 @@ func (s *Server) handleInitialized(ctx context.Context, params *lsproto.Initiali cwd = s.cwd } + // Read customConfigFileName from initializationOptions if provided + var customConfigFileName string + if s.initializeParams != nil && s.initializeParams.InitializationOptions != nil && *s.initializeParams.InitializationOptions != nil { + if m, ok := (*s.initializeParams.InitializationOptions).(map[string]any); ok { + if v, ok := m["customConfigFileName"].(string); ok { + customConfigFileName = v + } + } + } + s.session = project.NewSession(&project.SessionInit{ Options: &project.SessionOptions{ - CurrentDirectory: cwd, - DefaultLibraryPath: s.defaultLibraryPath, - TypingsLocation: s.typingsLocation, - PositionEncoding: s.positionEncoding, - WatchEnabled: s.watchEnabled, - LoggingEnabled: true, - DebounceDelay: 500 * time.Millisecond, + CurrentDirectory: cwd, + DefaultLibraryPath: s.defaultLibraryPath, + TypingsLocation: s.typingsLocation, + PositionEncoding: s.positionEncoding, + WatchEnabled: s.watchEnabled, + LoggingEnabled: true, + DebounceDelay: 500 * time.Millisecond, + CustomConfigFileName: customConfigFileName, }, FS: s.fs, Logger: s.logger, diff --git a/internal/project/configfileregistrybuilder.go b/internal/project/configfileregistrybuilder.go index 6dbb3c5f34..20c874ed9d 100644 --- a/internal/project/configfileregistrybuilder.go +++ b/internal/project/configfileregistrybuilder.go @@ -495,19 +495,37 @@ func (c *configFileRegistryBuilder) handleConfigChange(entry *dirty.SyncMapEntry func (c *configFileRegistryBuilder) computeConfigFileName(fileName string, skipSearchInDirectoryOfFile bool, logger *logging.LogTree) string { searchPath := tspath.GetDirectoryPath(fileName) + // Prefer custom config file if provided; search ancestors with correct skip behavior. + if c.sessionOptions.CustomConfigFileName != "" { + skipCustom := skipSearchInDirectoryOfFile + if result, _ := tspath.ForEachAncestorDirectory(searchPath, func(directory string) (result string, stop bool) { + customConfigFilePath := tspath.CombinePaths(directory, c.sessionOptions.CustomConfigFileName) + if !skipCustom && c.FS().FileExists(customConfigFilePath) { + return customConfigFilePath, true + } + skipCustom = false + return "", false + }); result != "" { + logger.Logf("computeConfigFileName:: File: %s:: Result: %s", fileName, result) + return result + } + } + + // Fallback to tsconfig.json/jsconfig.json + skip := skipSearchInDirectoryOfFile result, _ := tspath.ForEachAncestorDirectory(searchPath, func(directory string) (result string, stop bool) { tsconfigPath := tspath.CombinePaths(directory, "tsconfig.json") - if !skipSearchInDirectoryOfFile && c.FS().FileExists(tsconfigPath) { + if !skip && c.FS().FileExists(tsconfigPath) { return tsconfigPath, true } jsconfigPath := tspath.CombinePaths(directory, "jsconfig.json") - if !skipSearchInDirectoryOfFile && c.FS().FileExists(jsconfigPath) { + if !skip && c.FS().FileExists(jsconfigPath) { return jsconfigPath, true } if strings.HasSuffix(directory, "/node_modules") { return "", true } - skipSearchInDirectoryOfFile = false + skip = false return "", false }) logger.Logf("computeConfigFileName:: File: %s:: Result: %s", fileName, result) diff --git a/internal/project/session.go b/internal/project/session.go index 0e2b2de6b1..c1fda4515a 100644 --- a/internal/project/session.go +++ b/internal/project/session.go @@ -37,13 +37,14 @@ const ( // SessionOptions are the immutable initialization options for a session. // Snapshots may reference them as a pointer since they never change. type SessionOptions struct { - CurrentDirectory string - DefaultLibraryPath string - TypingsLocation string - PositionEncoding lsproto.PositionEncodingKind - WatchEnabled bool - LoggingEnabled bool - DebounceDelay time.Duration + CurrentDirectory string + DefaultLibraryPath string + TypingsLocation string + PositionEncoding lsproto.PositionEncodingKind + WatchEnabled bool + LoggingEnabled bool + DebounceDelay time.Duration + CustomConfigFileName string } type SessionInit struct {