diff --git a/src/vs/platform/workspaces/electron-main/workspacesHistoryMainService.ts b/src/vs/platform/workspaces/electron-main/workspacesHistoryMainService.ts index f174547116cdb7d900e45d8283fae1f4dd1583bc..d334381b5865280ed0059ad369a42d494d6e597d 100644 --- a/src/vs/platform/workspaces/electron-main/workspacesHistoryMainService.ts +++ b/src/vs/platform/workspaces/electron-main/workspacesHistoryMainService.ts @@ -6,7 +6,7 @@ import { localize } from 'vs/nls'; import { coalesce } from 'vs/base/common/arrays'; import { IStateService } from 'vs/platform/state/node/state'; -import { app, JumpListCategory } from 'electron'; +import { app, JumpListCategory, JumpListItem } from 'electron'; import { ILogService } from 'vs/platform/log/common/log'; import { getBaseLabel, getPathLabel, splitName } from 'vs/base/common/labels'; import { Event as CommonEvent, Emitter } from 'vs/base/common/event'; @@ -350,34 +350,40 @@ export class WorkspacesHistoryMainService extends Disposable implements IWorkspa this.removeRecentlyOpened(toRemove); // Add entries - jumpList.push({ - type: 'custom', - name: localize('recentFolders', "Recent Workspaces"), - items: coalesce(this.getRecentlyOpened().workspaces.slice(0, 7 /* limit number of entries here */).map(recent => { - const workspace = isRecentWorkspace(recent) ? recent.workspace : recent.folderUri; - const title = recent.label ? splitName(recent.label).name : this.getSimpleWorkspaceLabel(workspace, this.environmentService.untitledWorkspacesHome); - - let description; - let args; - if (isSingleFolderWorkspaceIdentifier(workspace)) { - description = localize('folderDesc', "{0} {1}", getBaseLabel(workspace), getPathLabel(dirname(workspace), this.environmentService)); - args = `--folder-uri "${workspace.toString()}"`; - } else { - description = localize('workspaceDesc', "{0} {1}", getBaseLabel(workspace.configPath), getPathLabel(dirname(workspace.configPath), this.environmentService)); - args = `--file-uri "${workspace.configPath.toString()}"`; - } + let hasWorkspaces = false; + const items: JumpListItem[] = coalesce(this.getRecentlyOpened().workspaces.slice(0, 7 /* limit number of entries here */).map(recent => { + const workspace = isRecentWorkspace(recent) ? recent.workspace : recent.folderUri; + const title = recent.label ? splitName(recent.label).name : this.getSimpleWorkspaceLabel(workspace, this.environmentService.untitledWorkspacesHome); + + let description; + let args; + if (isSingleFolderWorkspaceIdentifier(workspace)) { + description = localize('folderDesc', "{0} {1}", getBaseLabel(workspace), getPathLabel(dirname(workspace), this.environmentService)); + args = `--folder-uri "${workspace.toString()}"`; + } else { + hasWorkspaces = true; + description = localize('workspaceDesc', "{0} {1}", getBaseLabel(workspace.configPath), getPathLabel(dirname(workspace.configPath), this.environmentService)); + args = `--file-uri "${workspace.configPath.toString()}"`; + } - return { - type: 'task', - title: title.substr(0, 255), // Windows seems to be picky around the length of entries - description: description.substr(0, 255), // (see https://github.com/microsoft/vscode/issues/111177) - program: process.execPath, - args, - iconPath: 'explorer.exe', // simulate folder icon - iconIndex: 0 - }; - })) - }); + return { + type: 'task', + title: title.substr(0, 255), // Windows seems to be picky around the length of entries + description: description.substr(0, 255), // (see https://github.com/microsoft/vscode/issues/111177) + program: process.execPath, + args, + iconPath: 'explorer.exe', // simulate folder icon + iconIndex: 0 + }; + })); + + if (items.length > 0) { + jumpList.push({ + type: 'custom', + name: hasWorkspaces ? localize('recentFoldersAndWorkspaces', "Recent Folders & Workspaces") : localize('recentFolders', "Recent Folders"), + items + }); + } } // Recent diff --git a/src/vs/workbench/browser/actions/windowActions.ts b/src/vs/workbench/browser/actions/windowActions.ts index a65ee1a9e520f6fa9c2ca98a9969563e802ea59a..926527871e816d9efef6c58c0ae033145f161673 100644 --- a/src/vs/workbench/browser/actions/windowActions.ts +++ b/src/vs/workbench/browser/actions/windowActions.ts @@ -49,12 +49,17 @@ abstract class BaseOpenRecentAction extends Action { tooltip: nls.localize('remove', "Remove from Recently Opened") }; - private readonly dirtyRecentlyOpened: IQuickInputButton = { + private readonly dirtyRecentlyOpenedFolder: IQuickInputButton = { iconClass: 'dirty-workspace ' + Codicon.closeDirty.classNames, - tooltip: nls.localize('dirtyRecentlyOpened', "Workspace With Dirty Files"), + tooltip: nls.localize('dirtyRecentlyOpenedFolder', "Folder With Unsaved Files"), alwaysVisible: true }; + private readonly dirtyRecentlyOpenedWorkspace: IQuickInputButton = { + ...this.dirtyRecentlyOpenedFolder, + tooltip: nls.localize('dirtyRecentlyOpenedWorkspace', "Workspace With Unsaved Files"), + }; + constructor( id: string, label: string, @@ -77,7 +82,9 @@ abstract class BaseOpenRecentAction extends Action { const recentlyOpened = await this.workspacesService.getRecentlyOpened(); const dirtyWorkspacesAndFolders = await this.workspacesService.getDirtyWorkspaces(); - // Identify all folders and workspaces with dirty files + let hasWorkspaces = false; + + // Identify all folders and workspaces with unsaved files const dirtyFolders = new ResourceMap(); const dirtyWorkspaces = new ResourceMap(); for (const dirtyWorkspace of dirtyWorkspacesAndFolders) { @@ -85,6 +92,7 @@ abstract class BaseOpenRecentAction extends Action { dirtyFolders.set(dirtyWorkspace, true); } else { dirtyWorkspaces.set(dirtyWorkspace.configPath, dirtyWorkspace); + hasWorkspaces = true; } } @@ -96,6 +104,7 @@ abstract class BaseOpenRecentAction extends Action { recentFolders.set(recent.folderUri, true); } else { recentWorkspaces.set(recent.workspace.configPath, recent.workspace); + hasWorkspaces = true; } } @@ -124,7 +133,7 @@ abstract class BaseOpenRecentAction extends Action { let keyMods: IKeyMods | undefined; - const workspaceSeparator: IQuickPickSeparator = { type: 'separator', label: nls.localize('workspaces', "workspaces") }; + const workspaceSeparator: IQuickPickSeparator = { type: 'separator', label: hasWorkspaces ? nls.localize('workspacesAndFolders', "folders & workspaces") : nls.localize('folders', "folders") }; const fileSeparator: IQuickPickSeparator = { type: 'separator', label: nls.localize('files', "files") }; const picks = [workspaceSeparator, ...workspacePicks, fileSeparator, ...filePicks]; @@ -143,13 +152,14 @@ abstract class BaseOpenRecentAction extends Action { context.removeItem(); } - // Dirty Workspace - else if (context.button === this.dirtyRecentlyOpened) { + // Dirty Folder/Workspace + else if (context.button === this.dirtyRecentlyOpenedFolder || context.button === this.dirtyRecentlyOpenedWorkspace) { + const isDirtyWorkspace = context.button === this.dirtyRecentlyOpenedWorkspace; const result = await this.dialogService.confirm({ type: 'question', - title: nls.localize('dirtyWorkspace', "Workspace with Dirty Files"), - message: nls.localize('dirtyWorkspaceConfirm', "Do you want to open the workspace to review the dirty files?"), - detail: nls.localize('dirtyWorkspaceConfirmDetail', "Workspaces with dirty files cannot be removed until all dirty files have been saved or reverted.") + title: isDirtyWorkspace ? nls.localize('dirtyWorkspace', "Workspace with Unsaved Files") : nls.localize('dirtyFolder', "Folder with Unsaved Files"), + message: isDirtyWorkspace ? nls.localize('dirtyWorkspaceConfirm', "Do you want to open the workspace to review the unsaved files?") : nls.localize('dirtyFolderConfirm', "Do you want to open the folder to review the unsaved files?"), + detail: isDirtyWorkspace ? nls.localize('dirtyWorkspaceConfirmDetail', "Workspaces with unsaved files cannot be removed until all unsaved files have been saved or reverted.") : nls.localize('dirtyFolderConfirmDetail', "Folders with unsaved files cannot be removed until all unsaved files have been saved or reverted.") }); if (result.confirmed) { @@ -170,6 +180,7 @@ abstract class BaseOpenRecentAction extends Action { let iconClasses: string[]; let fullLabel: string | undefined; let resource: URI | undefined; + let isWorkspace = false; // Folder if (isRecentFolder(recent)) { @@ -185,6 +196,7 @@ abstract class BaseOpenRecentAction extends Action { iconClasses = getIconClasses(this.modelService, this.modeService, resource, FileKind.ROOT_FOLDER); openable = { workspaceUri: resource }; fullLabel = recent.label || this.labelService.getWorkspaceLabel(recent.workspace, { verbose: true }); + isWorkspace = true; } // File @@ -200,9 +212,9 @@ abstract class BaseOpenRecentAction extends Action { return { iconClasses, label: name, - ariaLabel: isDirty ? nls.localize('recentDirtyAriaLabel', "{0}, dirty workspace", name) : name, + ariaLabel: isDirty ? isWorkspace ? nls.localize('recentDirtyWorkspaceAriaLabel', "{0}, workspace with unsaved changes", name) : nls.localize('recentDirtyFolderAriaLabel', "{0}, folder with unsaved changes", name) : name, description: parentPath, - buttons: isDirty ? [this.dirtyRecentlyOpened] : [this.removeFromRecentlyOpened], + buttons: isDirty ? [isWorkspace ? this.dirtyRecentlyOpenedWorkspace : this.dirtyRecentlyOpenedFolder] : [this.removeFromRecentlyOpened], openable, resource }; diff --git a/src/vs/workbench/browser/actions/workspaceActions.ts b/src/vs/workbench/browser/actions/workspaceActions.ts index b735737600f69aba80c3064f0e37202a35c57775..f1cb06bdc538441ddbb92d4d6fd87d5583f37cff 100644 --- a/src/vs/workbench/browser/actions/workspaceActions.ts +++ b/src/vs/workbench/browser/actions/workspaceActions.ts @@ -114,7 +114,7 @@ export class CloseWorkspaceAction extends Action { async run(): Promise { if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) { - this.notificationService.info(nls.localize('noWorkspaceOpened', "There is currently no workspace opened in this instance to close.")); + this.notificationService.info(nls.localize('noWorkspaceOrFolderOpened', "There is currently no workspace or folder opened in this instance to close.")); return; } diff --git a/src/vs/workbench/browser/workbench.contribution.ts b/src/vs/workbench/browser/workbench.contribution.ts index d5ea96380a9d93b398b6b72a9379cf151a09bc6d..270463eed9440e03026510ec9246fc460bed09ff 100644 --- a/src/vs/workbench/browser/workbench.contribution.ts +++ b/src/vs/workbench/browser/workbench.contribution.ts @@ -330,8 +330,8 @@ import { isStandalone } from 'vs/base/browser/browser'; nls.localize('activeFolderLong', "`\${activeFolderLong}`: the full path of the folder the file is contained in (e.g. /Users/Development/myFolder/myFileFolder)."), nls.localize('folderName', "`\${folderName}`: name of the workspace folder the file is contained in (e.g. myFolder)."), nls.localize('folderPath', "`\${folderPath}`: file path of the workspace folder the file is contained in (e.g. /Users/Development/myFolder)."), - nls.localize('rootName', "`\${rootName}`: name of the workspace (e.g. myFolder or myWorkspace)."), - nls.localize('rootPath', "`\${rootPath}`: file path of the workspace (e.g. /Users/Development/myWorkspace)."), + nls.localize('rootName', "`\${rootName}`: name of the opened workspace or folder (e.g. myFolder or myWorkspace)."), + nls.localize('rootPath', "`\${rootPath}`: file path of the opened workspace or folder (e.g. /Users/Development/myWorkspace)."), nls.localize('appName', "`\${appName}`: e.g. VS Code."), nls.localize('remoteName', "`\${remoteName}`: e.g. SSH"), nls.localize('dirty', "`\${dirty}`: a dirty indicator if the active editor is dirty."), diff --git a/src/vs/workbench/common/theme.ts b/src/vs/workbench/common/theme.ts index 53f29efbd4cf8f5e632db0651a4474d58094ca37..317cfd2fcd99b559029b74e06d6207b8d300cb2a 100644 --- a/src/vs/workbench/common/theme.ts +++ b/src/vs/workbench/common/theme.ts @@ -339,7 +339,7 @@ export const STATUS_BAR_FOREGROUND = registerColor('statusBar.foreground', { dark: '#FFFFFF', light: '#FFFFFF', hc: '#FFFFFF' -}, nls.localize('statusBarForeground', "Status bar foreground color when a workspace is opened. The status bar is shown in the bottom of the window.")); +}, nls.localize('statusBarForeground', "Status bar foreground color when a workspace or folder is opened. The status bar is shown in the bottom of the window.")); export const STATUS_BAR_NO_FOLDER_FOREGROUND = registerColor('statusBar.noFolderForeground', { dark: STATUS_BAR_FOREGROUND, @@ -351,7 +351,7 @@ export const STATUS_BAR_BACKGROUND = registerColor('statusBar.background', { dark: '#007ACC', light: '#007ACC', hc: null -}, nls.localize('statusBarBackground', "Status bar background color when a workspace is opened. The status bar is shown in the bottom of the window.")); +}, nls.localize('statusBarBackground', "Status bar background color when a workspace or folder is opened. The status bar is shown in the bottom of the window.")); export const STATUS_BAR_NO_FOLDER_BACKGROUND = registerColor('statusBar.noFolderBackground', { dark: '#68217A', diff --git a/src/vs/workbench/contrib/files/browser/files.contribution.ts b/src/vs/workbench/contrib/files/browser/files.contribution.ts index dfac8e99d7e5ad5bdc1e99c29c5bb8e2c777de7f..addb357254799b85e5472248d46e896281710765 100644 --- a/src/vs/workbench/contrib/files/browser/files.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/files.contribution.ts @@ -198,8 +198,8 @@ const hotExitConfiguration: IConfigurationPropertySchema = platform.isNative ? 'default': HotExitConfiguration.ON_EXIT, 'markdownEnumDescriptions': [ nls.localize('hotExit.off', 'Disable hot exit. A prompt will show when attempting to close a window with dirty files.'), - nls.localize('hotExit.onExit', 'Hot exit will be triggered when the last window is closed on Windows/Linux or when the `workbench.action.quit` command is triggered (command palette, keybinding, menu). All windows without folders opened will be restored upon next launch. A list of workspaces with unsaved files can be accessed via `File > Open Recent > More...`'), - nls.localize('hotExit.onExitAndWindowClose', 'Hot exit will be triggered when the last window is closed on Windows/Linux or when the `workbench.action.quit` command is triggered (command palette, keybinding, menu), and also for any window with a folder opened regardless of whether it\'s the last window. All windows without folders opened will be restored upon next launch. A list of workspaces with unsaved files can be accessed via `File > Open Recent > More...`') + nls.localize('hotExit.onExit', 'Hot exit will be triggered when the last window is closed on Windows/Linux or when the `workbench.action.quit` command is triggered (command palette, keybinding, menu). All windows without folders opened will be restored upon next launch. A list of previously opened windows with unsaved files can be accessed via `File > Open Recent > More...`'), + nls.localize('hotExit.onExitAndWindowClose', 'Hot exit will be triggered when the last window is closed on Windows/Linux or when the `workbench.action.quit` command is triggered (command palette, keybinding, menu), and also for any window with a folder opened regardless of whether it\'s the last window. All windows without folders opened will be restored upon next launch. A list of previously opened windows with unsaved files can be accessed via `File > Open Recent > More...`') ], 'description': nls.localize('hotExit', "Controls whether unsaved files are remembered between sessions, allowing the save prompt when exiting the editor to be skipped.", HotExitConfiguration.ON_EXIT, HotExitConfiguration.ON_EXIT_AND_WINDOW_CLOSE) } : { diff --git a/src/vs/workbench/contrib/files/common/workspaceWatcher.ts b/src/vs/workbench/contrib/files/common/workspaceWatcher.ts index 04bfd96daba5ff4fb1e8537a0b2c2a2166826f5e..1534bdc86083dd0c95b317ac01112ce8b7b75f33 100644 --- a/src/vs/workbench/contrib/files/common/workspaceWatcher.ts +++ b/src/vs/workbench/contrib/files/common/workspaceWatcher.ts @@ -89,7 +89,7 @@ export class WorkspaceWatcher extends Disposable { if (msg.indexOf('ENOSPC') >= 0) { this.notificationService.prompt( Severity.Warning, - localize('enospcError', "Unable to watch for file changes in this large workspace. Please follow the instructions link to resolve this issue."), + localize('enospcError', "Unable to watch for file changes in this large workspace folder. Please follow the instructions link to resolve this issue."), [{ label: localize('learnMore', "Instructions"), run: () => this.openerService.open(URI.parse('https://go.microsoft.com/fwlink/?linkid=867693')) diff --git a/src/vs/workbench/contrib/search/browser/search.contribution.ts b/src/vs/workbench/contrib/search/browser/search.contribution.ts index b0ccc88477d6db977f0f327286cd0199967a6f4a..4b99bee21d608a6b04b9df6dabc2640f796fb433 100644 --- a/src/vs/workbench/contrib/search/browser/search.contribution.ts +++ b/src/vs/workbench/contrib/search/browser/search.contribution.ts @@ -840,7 +840,7 @@ configurationRegistry.registerConfiguration({ 'search.seedOnFocus': { type: 'boolean', default: false, - description: nls.localize('search.seedOnFocus', "Update workspace search query to the editor's selected text when focusing the search view. This happens either on click or when triggering the `workbench.views.search.focus` command.") + description: nls.localize('search.seedOnFocus', "Update the search query to the editor's selected text when focusing the search view. This happens either on click or when triggering the `workbench.views.search.focus` command.") }, 'search.searchOnTypeDebouncePeriod': { type: 'number', diff --git a/src/vs/workbench/contrib/search/common/queryBuilder.ts b/src/vs/workbench/contrib/search/common/queryBuilder.ts index 7a99e055745a39ba04dffa4e19fd6dc4cec5e39b..c7b9d17e10a347683726c724b8c843f1b619752e 100644 --- a/src/vs/workbench/contrib/search/common/queryBuilder.ts +++ b/src/vs/workbench/contrib/search/common/queryBuilder.ts @@ -378,7 +378,7 @@ export class QueryBuilder { }); } else { // No root folder with name - const searchPathNotFoundError = nls.localize('search.noWorkspaceWithName', "No folder in workspace with name: {0}", searchPathRoot); + const searchPathNotFoundError = nls.localize('search.noWorkspaceWithName', "Workspace folder does not exist: {0}", searchPathRoot); throw new Error(searchPathNotFoundError); } } else { diff --git a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts index 436edea336ce5831a2b65621383d15be3d52c196..474487e567405a2a2a432dc99599d60c8dd1fad0 100644 --- a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts +++ b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts @@ -1977,7 +1977,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer await this.computeTasksForSingleConfig(workspaceFolder, configuration.config, runSource, custom, customizedTasks.byIdentifier, TaskConfig.TaskConfigSource.WorkspaceFile); const engine = configuration.config ? TaskConfig.ExecutionEngine.from(configuration.config) : ExecutionEngine.Terminal; if (engine === ExecutionEngine.Process) { - this.notificationService.warn(nls.localize('TaskSystem.versionWorkspaceFile', 'Only tasks version 2.0.0 permitted in .codeworkspace.')); + this.notificationService.warn(nls.localize('TaskSystem.versionWorkspaceFile', 'Only tasks version 2.0.0 permitted in workspace configuration files.')); return this.emptyWorkspaceTaskResults(workspaceFolder); } return { workspaceFolder, set: { tasks: custom }, configurations: customizedTasks, hasErrors: configuration.hasParseErrors }; diff --git a/src/vs/workbench/contrib/welcome/page/browser/welcomePage.contribution.ts b/src/vs/workbench/contrib/welcome/page/browser/welcomePage.contribution.ts index 1a59cbb17c471c1dcf2fc2dbc12255596f05b343..141a92340ec59e6a4d1f0fb2a7a1a97efa6a62a6 100644 --- a/src/vs/workbench/contrib/welcome/page/browser/welcomePage.contribution.ts +++ b/src/vs/workbench/contrib/welcome/page/browser/welcomePage.contribution.ts @@ -32,7 +32,7 @@ Registry.as(ConfigurationExtensions.Configuration) localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.startupEditor.none' }, "Start without an editor."), localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.startupEditor.welcomePage' }, "Open the Welcome page (default)."), localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.startupEditor.readme' }, "Open the README when opening a folder that contains one, fallback to 'welcomePage' otherwise."), - localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.startupEditor.newUntitledFile' }, "Open a new untitled file (only applies when opening an empty workspace)."), + localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.startupEditor.newUntitledFile' }, "Open a new untitled file (only applies when opening an empty window)."), localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.startupEditor.welcomePageInEmptyWorkbench' }, "Open the Welcome page when opening an empty workbench."),], ...(product.quality !== 'stable' ? [localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.startupEditor.gettingStarted' }, "Open the Getting Started page (experimental).")] diff --git a/src/vs/workbench/services/preferences/browser/preferencesService.ts b/src/vs/workbench/services/preferences/browser/preferencesService.ts index 7cf56fbc39d24630abf0ddc3507ab894ac9c700e..15078ac482c3d4c38a452115ce2af3c72193804b 100644 --- a/src/vs/workbench/services/preferences/browser/preferencesService.ts +++ b/src/vs/workbench/services/preferences/browser/preferencesService.ts @@ -246,7 +246,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic jsonEditor; if (!this.workspaceSettingsResource) { - this.notificationService.info(nls.localize('openFolderFirst', "Open a folder first to create workspace settings")); + this.notificationService.info(nls.localize('openFolderFirst', "Open a folder or workspace first to create workspace or folder settings.")); return Promise.reject(null); }