diff --git a/extensions/typescript/package.json b/extensions/typescript/package.json index 415686fe9c980..652728d8a17ca 100644 --- a/extensions/typescript/package.json +++ b/extensions/typescript/package.json @@ -33,7 +33,9 @@ "onLanguage:jsx-tags", "onCommand:typescript.reloadProjects", "onCommand:javascript.reloadProjects", - "onCommand:typescript.selectTypeScriptVersion" + "onCommand:typescript.selectTypeScriptVersion", + "onCommand:javascript.goToProjectConfig", + "onCommand:typescript.goToProjectConfig" ], "main": "./out/typescriptMain", "enableProposedApi": true, @@ -257,15 +259,28 @@ "commands": [ { "command": "typescript.reloadProjects", - "title": "%typescript.reloadProjects.title%" + "title": "%typescript.reloadProjects.title%", + "category": "TypeScript" }, { "command": "javascript.reloadProjects", - "title": "%javascript.reloadProjects.title%" + "title": "%javascript.reloadProjects.title%", + "category": "JavaScript" }, { "command": "typescript.selectTypeScriptVersion", - "title": "%typescript.selectTypeScriptVersion.title%" + "title": "%typescript.selectTypeScriptVersion.title%", + "category": "TypeScript" + }, + { + "command": "typescript.goToProjectConfig", + "title": "%typescript.goToProjectConfig.title%", + "category": "TypeScript" + }, + { + "command": "javascript.goToProjectConfig", + "title": "%javascript.goToProjectConfig.title%", + "category": "JavaScript" } ], "breakpoints": [ @@ -301,4 +316,4 @@ } ] } -} +} \ No newline at end of file diff --git a/extensions/typescript/package.nls.json b/extensions/typescript/package.nls.json index 2d1589b98cf4d..d925d83f77964 100644 --- a/extensions/typescript/package.nls.json +++ b/extensions/typescript/package.nls.json @@ -1,6 +1,6 @@ { - "typescript.reloadProjects.title": "Reload TypeScript Project", - "javascript.reloadProjects.title": "Reload JavaScript Project", + "typescript.reloadProjects.title": "Reload Project", + "javascript.reloadProjects.title": "Reload Project", "configuration.typescript": "TypeScript", "typescript.useCodeSnippetsOnMethodSuggest.dec": "Complete functions with their parameter signature.", "typescript.tsdk.desc": "Specifies the folder path containing the tsserver and lib*.d.ts files to use.", @@ -24,6 +24,8 @@ "format.placeOpenBraceOnNewLineForFunctions": "Defines whether an open brace is put onto a new line for functions or not.", "format.placeOpenBraceOnNewLineForControlBlocks": "Defines whether an open brace is put onto a new line for control blocks or not.", "javascript.validate.enable": "Enable/disable JavaScript validation.", + "typescript.goToProjectConfig.title": "Go to Project Configuration", + "javascript.goToProjectConfig.title": "Go to Project Configuration", "typescript.referencesCodeLens.enabled": "Enable/disable the references code lens.", - "typescript.selectTypeScriptVersion.title": "Select TypeScript version." + "typescript.selectTypeScriptVersion.title": "Select TypeScript Version" } \ No newline at end of file diff --git a/extensions/typescript/src/typescriptMain.ts b/extensions/typescript/src/typescriptMain.ts index 2fe25d90d57f6..dad29a5ea3f7a 100644 --- a/extensions/typescript/src/typescriptMain.ts +++ b/extensions/typescript/src/typescriptMain.ts @@ -9,12 +9,13 @@ * ------------------------------------------------------------------------------------------ */ 'use strict'; -import { env, languages, commands, workspace, window, ExtensionContext, Memento, IndentAction, Diagnostic, DiagnosticCollection, Range, DocumentFilter, Disposable, Uri } from 'vscode'; +import { env, languages, commands, workspace, window, ExtensionContext, Memento, IndentAction, Diagnostic, DiagnosticCollection, Range, DocumentFilter, Disposable, Uri, MessageItem, TextEditor } from 'vscode'; // This must be the first statement otherwise modules might got loaded with // the wrong locale. import * as nls from 'vscode-nls'; nls.config({ locale: env.language }); +const localize = nls.loadMessageBundle(); import * as path from 'path'; @@ -52,6 +53,16 @@ interface LanguageDescription { configFile: string; } +enum ProjectConfigAction { + None, + CreateConfig, + LearnMore +} + +interface ProjectConfigMessageItem extends MessageItem { + id: ProjectConfigAction; +} + export function activate(context: ExtensionContext): void { const MODE_ID_TS = 'typescript'; const MODE_ID_TSX = 'typescriptreact'; @@ -89,6 +100,15 @@ export function activate(context: ExtensionContext): void { client.onVersionStatusClicked(); })); + const goToProjectConfig = (isTypeScript: boolean) => { + const editor = window.activeTextEditor; + if (editor) { + clientHost.goToProjectConfig(isTypeScript, editor.document.uri, editor.document.languageId); + } + }; + context.subscriptions.push(commands.registerCommand('typescript.goToProjectConfig', goToProjectConfig.bind(null, true))); + context.subscriptions.push(commands.registerCommand('javascript.goToProjectConfig', goToProjectConfig.bind(null, false))); + window.onDidChangeActiveTextEditor(VersionStatus.showHideStatus, null, context.subscriptions); client.onReady().then(() => { context.subscriptions.push(ProjectStatus.create(client, @@ -378,6 +398,76 @@ class TypeScriptServiceClientHost implements ITypescriptServiceClientHost { return !!this.findLanguage(file); } + public goToProjectConfig( + isTypeScriptProject: boolean, + resource: Uri, + languageId: string + ): Thenable | undefined { + const rootPath = workspace.rootPath; + if (!rootPath) { + window.showInformationMessage( + localize( + 'typescript.projectConfigNoWorkspace', + 'Please open a folder in VS Code to use a TypeScript or JavaScript project')); + return; + } + + const file = this.client.normalizePath(resource); + // TODO: TSServer errors when 'projectInfo' is invoked on a non js/ts file + if (!file || !this.languagePerId[languageId]) { + window.showWarningMessage( + localize( + 'typescript.projectConfigUnsupportedFile', + 'Could not determine TypeScript or JavaScript project. Unsupported file type')); + return; + } + + return this.client.execute('projectInfo', { file, needFileNameList: false }).then(res => { + if (!res || !res.body) { + return window.showWarningMessage(localize('typescript.projectConfigCouldNotGetInfo', 'Could not determine TypeScript or JavaScript project')); + } + + const { configFileName } = res.body; + if (configFileName && configFileName.indexOf('/dev/null/') !== 0) { + return workspace.openTextDocument(configFileName) + .then(window.showTextDocument); + } + + return window.showInformationMessage( + (isTypeScriptProject + ? localize('typescript.noTypeScriptProjectConfig', 'File is not part of a TypeScript project') + : localize('typescript.noJavaScriptProjectConfig', 'File is not part of a JavaScript project') + ), { + title: isTypeScriptProject + ? localize('typescript.configureTsconfigQuickPick', 'Configure tsconfig.json') + : localize('typescript.configureJsconfigQuickPick', 'Configure jsconfig.json'), + id: ProjectConfigAction.CreateConfig + }, { + title: localize('typescript.projectConfigLearnMore', 'Learn More'), + id: ProjectConfigAction.LearnMore + }).then(selected => { + switch (selected && selected.id) { + case ProjectConfigAction.CreateConfig: + const configFile = Uri.file(path.join(rootPath, isTypeScriptProject ? 'tsconfig.json' : 'jsconfig.json')); + return workspace.openTextDocument(configFile) + .then(undefined, _ => workspace.openTextDocument(configFile.with({ scheme: 'untitled' }))) + .then(window.showTextDocument); + + case ProjectConfigAction.LearnMore: + if (isTypeScriptProject) { + commands.executeCommand('vscode.open', Uri.parse('https://go.microsoft.com/fwlink/?linkid=841896')); + } else { + commands.executeCommand('vscode.open', Uri.parse('https://go.microsoft.com/fwlink/?linkid=759670')); + } + return; + + default: + return Promise.resolve(undefined); + } + }); + }); + } + private findLanguage(file: string): LanguageProvider | null { for (let i = 0; i < this.languages.length; i++) { let language = this.languages[i];