files.contribution.ts 15.7 KB
Newer Older
E
Erich Gamma 已提交
1 2 3 4 5 6 7 8
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

'use strict';

import URI from 'vs/base/common/uri';
9
import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor, ToggleViewletAction } from 'vs/workbench/browser/viewlet';
E
Erich Gamma 已提交
10
import nls = require('vs/nls');
11 12 13 14 15 16
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
import { Registry } from 'vs/platform/platform';
import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry';
import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actionRegistry';
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
import { IEditorRegistry, Extensions as EditorExtensions, IEditorInputFactory, EditorInput, IFileEditorInput } from 'vs/workbench/common/editor';
17
import { AutoSaveConfiguration, HotExitConfiguration, SUPPORTED_ENCODINGS, IFilesConfiguration } from 'vs/platform/files/common/files';
B
Benjamin Pasero 已提交
18
import { EditorDescriptor } from 'vs/workbench/browser/parts/editor/baseEditor';
19 20 21 22 23 24 25
import { FILE_EDITOR_INPUT_ID, VIEWLET_ID } from 'vs/workbench/parts/files/common/files';
import { FileEditorTracker } from 'vs/workbench/parts/files/common/editors/fileEditorTracker';
import { SaveErrorHandler } from 'vs/workbench/parts/files/browser/saveErrorHandler';
import { FileEditorInput } from 'vs/workbench/parts/files/common/editors/fileEditorInput';
import { TextFileEditor } from 'vs/workbench/parts/files/browser/editors/textFileEditor';
import { BinaryFileEditor } from 'vs/workbench/parts/files/browser/editors/binaryFileEditor';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
26
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
A
Renames  
Alex Dima 已提交
27
import { IKeybindings } from 'vs/platform/keybinding/common/keybindingsRegistry';
B
Benjamin Pasero 已提交
28
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
29 30
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
31
import * as platform from 'vs/base/common/platform';
32
import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration';
33
import { DirtyFilesTracker } from 'vs/workbench/parts/files/common/dirtyFilesTracker';
E
Erich Gamma 已提交
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50

// Viewlet Action
export class OpenExplorerViewletAction extends ToggleViewletAction {
	public static ID = VIEWLET_ID;
	public static LABEL = nls.localize('showExplorerViewlet', "Show Explorer");

	constructor(
		id: string,
		label: string,
		@IViewletService viewletService: IViewletService,
		@IWorkbenchEditorService editorService: IWorkbenchEditorService
	) {
		super(id, label, VIEWLET_ID, viewletService, editorService);
	}
}

// Register Viewlet
B
Benjamin Pasero 已提交
51
Registry.as<ViewletRegistry>(ViewletExtensions.Viewlets).registerViewlet(new ViewletDescriptor(
E
Erich Gamma 已提交
52 53 54
	'vs/workbench/parts/files/browser/explorerViewlet',
	'ExplorerViewlet',
	VIEWLET_ID,
B
Benjamin Pasero 已提交
55
	nls.localize('explore', "Explorer"),
E
Erich Gamma 已提交
56 57 58 59
	'explore',
	0
));

B
Benjamin Pasero 已提交
60
Registry.as<ViewletRegistry>(ViewletExtensions.Viewlets).setDefaultViewletId(VIEWLET_ID);
E
Erich Gamma 已提交
61

B
Benjamin Pasero 已提交
62
const openViewletKb: IKeybindings = {
E
Erich Gamma 已提交
63 64 65 66
	primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_E
};

// Register Action to Open Viewlet
B
Benjamin Pasero 已提交
67
const registry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
68
registry.registerWorkbenchAction(
E
Erich Gamma 已提交
69
	new SyncActionDescriptor(OpenExplorerViewletAction, OpenExplorerViewletAction.ID, OpenExplorerViewletAction.LABEL, openViewletKb),
70
	'View: Show Explorer',
71
	nls.localize('view', "View")
E
Erich Gamma 已提交
72 73 74
);

// Register file editors
B
Benjamin Pasero 已提交
75
Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditor(
B
Benjamin Pasero 已提交
76
	new EditorDescriptor(
77
		TextFileEditor.ID, // explicit dependency because we don't want these editors lazy loaded
E
Erich Gamma 已提交
78 79
		nls.localize('textFileEditor', "Text File Editor"),
		'vs/workbench/parts/files/browser/editors/textFileEditor',
B
Benjamin Pasero 已提交
80
		'TextFileEditor'
E
Erich Gamma 已提交
81 82 83 84 85 86
	),
	[
		new SyncDescriptor<EditorInput>(FileEditorInput)
	]
);

B
Benjamin Pasero 已提交
87
Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditor(
B
Benjamin Pasero 已提交
88
	new EditorDescriptor(
89
		BinaryFileEditor.ID, // explicit dependency because we don't want these editors lazy loaded
E
Erich Gamma 已提交
90 91
		nls.localize('binaryFileEditor', "Binary File Editor"),
		'vs/workbench/parts/files/browser/editors/binaryFileEditor',
B
Benjamin Pasero 已提交
92
		'BinaryFileEditor'
E
Erich Gamma 已提交
93 94 95 96 97 98
	),
	[
		new SyncDescriptor<EditorInput>(FileEditorInput)
	]
);

99 100 101 102 103 104
// Register default file input factory
Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerFileInputFactory({
	createFileInput: (resource, encoding, instantiationService): IFileEditorInput => {
		return instantiationService.createInstance(FileEditorInput, resource, encoding);
	}
});
E
Erich Gamma 已提交
105 106

interface ISerializedFileInput {
107 108
	resource: string;
	resourceJSON: any;
109
	encoding?: string;
E
Erich Gamma 已提交
110 111 112 113
}

// Register Editor Input Factory
class FileEditorInputFactory implements IEditorInputFactory {
114
	private configuredEncoding: string;
E
Erich Gamma 已提交
115

116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
	constructor(
		@IWorkspaceConfigurationService private configurationService: IWorkspaceConfigurationService
	) {
		this.onConfiguration(configurationService.getConfiguration<IFilesConfiguration>());

		this.registerListeners();
	}

	private registerListeners(): void {
		this.configurationService.onDidUpdateConfiguration(e => this.onConfiguration(e.config));
	}

	private onConfiguration(config: IFilesConfiguration): void {
		this.configuredEncoding = config.files && config.files.encoding;
	}
E
Erich Gamma 已提交
131 132

	public serialize(editorInput: EditorInput): string {
B
Benjamin Pasero 已提交
133
		const fileEditorInput = <FileEditorInput>editorInput;
134
		const resource = fileEditorInput.getResource();
B
Benjamin Pasero 已提交
135
		const fileInput: ISerializedFileInput = {
136 137
			resource: resource.toString(), // Keep for backwards compatibility
			resourceJSON: resource.toJSON()
E
Erich Gamma 已提交
138 139
		};

140 141 142 143 144
		const encoding = fileEditorInput.getPreferredEncoding();
		if (encoding && encoding !== this.configuredEncoding) {
			fileInput.encoding = encoding;
		}

E
Erich Gamma 已提交
145 146 147
		return JSON.stringify(fileInput);
	}

148 149 150 151 152
	public deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): FileEditorInput {
		return instantiationService.invokeFunction<FileEditorInput>(accessor => {
			const fileInput: ISerializedFileInput = JSON.parse(serializedEditorInput);
			const resource = !!fileInput.resourceJSON ? URI.revive(fileInput.resourceJSON) : URI.parse(fileInput.resource);
			const encoding = fileInput.encoding;
E
Erich Gamma 已提交
153

154 155
			return accessor.get(IWorkbenchEditorService).createInput({ resource, encoding }) as FileEditorInput;
		});
E
Erich Gamma 已提交
156 157 158
	}
}

B
Benjamin Pasero 已提交
159
Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditorInputFactory(FILE_EDITOR_INPUT_ID, FileEditorInputFactory);
E
Erich Gamma 已提交
160

161
// Register File Editor Tracker
B
Benjamin Pasero 已提交
162
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(
163
	FileEditorTracker
E
Erich Gamma 已提交
164 165
);

B
Benjamin Pasero 已提交
166 167 168 169 170
// Register Save Error Handler
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(
	SaveErrorHandler
);

171 172 173 174 175
// Register Dirty Files Tracker
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(
	DirtyFilesTracker
);

E
Erich Gamma 已提交
176
// Configuration
B
Benjamin Pasero 已提交
177
const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);
E
Erich Gamma 已提交
178 179 180

configurationRegistry.registerConfiguration({
	'id': 'files',
181
	'order': 9,
182
	'title': nls.localize('filesConfigurationTitle', "Files"),
E
Erich Gamma 已提交
183 184 185 186 187
	'type': 'object',
	'properties': {
		'files.exclude': {
			'type': 'object',
			'description': nls.localize('exclude', "Configure glob patterns for excluding files and folders."),
P
Peter V 已提交
188
			'default': { '**/.git': true, '**/.svn': true, '**/.hg': true, '**/CVS': true, '**/.DS_Store': true },
E
Erich Gamma 已提交
189 190 191 192 193 194 195 196 197 198 199 200 201
			'additionalProperties': {
				'anyOf': [
					{
						'type': 'boolean',
						'description': nls.localize('files.exclude.boolean', "The glob pattern to match file paths against. Set to true or false to enable or disable the pattern."),
					},
					{
						'type': 'object',
						'properties': {
							'when': {
								'type': 'string', // expression ({ "**/*.js": { "when": "$(basename).js" } })
								'pattern': '\\w*\\$\\(basename\\)\\w*',
								'default': '$(basename).ext',
B
Benjamin Pasero 已提交
202
								'description': nls.localize('files.exclude.when', "Additional check on the siblings of a matching file. Use $(basename) as variable for the matching file name.")
E
Erich Gamma 已提交
203 204 205 206 207 208
							}
						}
					}
				]
			}
		},
B
Benjamin Pasero 已提交
209
		'files.associations': {
210
			'type': 'object',
B
Benjamin Pasero 已提交
211
			'description': nls.localize('associations', "Configure file associations to languages (e.g. \"*.extension\": \"html\"). These have precedence over the default associations of the languages installed."),
212
		},
E
Erich Gamma 已提交
213 214 215 216 217 218
		'files.encoding': {
			'type': 'string',
			'enum': Object.keys(SUPPORTED_ENCODINGS),
			'default': 'utf8',
			'description': nls.localize('encoding', "The default character set encoding to use when reading and writing files."),
		},
219
		'files.autoGuessEncoding': {
220 221
			'type': 'boolean',
			'default': false,
222
			'description': nls.localize('autoGuessEncoding', "When enabled, will attempt to guess the character set encoding when opening files")
223
		},
224 225 226 227 228 229 230
		'files.eol': {
			'type': 'string',
			'enum': [
				'\n',
				'\r\n'
			],
			'default': (platform.isLinux || platform.isMacintosh) ? '\n' : '\r\n',
231
			'description': nls.localize('eol', "The default end of line character. Use \\n for LF and \\r\\n for CRLF."),
232
		},
E
Erich Gamma 已提交
233 234 235
		'files.trimTrailingWhitespace': {
			'type': 'boolean',
			'default': false,
236 237
			'description': nls.localize('trimTrailingWhitespace', "When enabled, will trim trailing whitespace when saving a file."),
			'overridable': true
238 239 240 241
		},
		'files.insertFinalNewline': {
			'type': 'boolean',
			'default': false,
242 243
			'description': nls.localize('insertFinalNewline', "When enabled, insert a final new line at the end of the file when saving it."),
			'overridable': true
244
		},
245 246
		'files.autoSave': {
			'type': 'string',
S
Sandeep Somavarapu 已提交
247
			'enum': [AutoSaveConfiguration.OFF, AutoSaveConfiguration.AFTER_DELAY, AutoSaveConfiguration.ON_FOCUS_CHANGE, , AutoSaveConfiguration.ON_WINDOW_CHANGE],
248
			'enumDescriptions': [
249 250 251 252
				nls.localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'files.autoSave.off' }, "A dirty file is never automatically saved."),
				nls.localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'files.autoSave.afterDelay' }, "A dirty file is automatically saved after the configured 'files.autoSaveDelay'."),
				nls.localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'files.autoSave.onFocusChange' }, "A dirty file is automatically saved when the editor loses focus."),
				nls.localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'files.autoSave.onWindowChange' }, "A dirty file is automatically saved when the window loses focus.")
253
			],
254
			'default': AutoSaveConfiguration.OFF,
B
Benjamin Pasero 已提交
255
			'description': nls.localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'autoSave' }, "Controls auto save of dirty files. Accepted values:  '{0}', '{1}', '{2}' (editor loses focus), '{3}' (window loses focus). If set to '{4}', you can configure the delay in 'files.autoSaveDelay'.", AutoSaveConfiguration.OFF, AutoSaveConfiguration.AFTER_DELAY, AutoSaveConfiguration.ON_FOCUS_CHANGE, AutoSaveConfiguration.ON_WINDOW_CHANGE, AutoSaveConfiguration.AFTER_DELAY)
256
		},
257
		'files.autoSaveDelay': {
258
			'type': 'number',
259
			'default': 1000,
B
Benjamin Pasero 已提交
260
			'description': nls.localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'autoSaveDelay' }, "Controls the delay in ms after which a dirty file is saved automatically. Only applies when 'files.autoSave' is set to '{0}'", AutoSaveConfiguration.AFTER_DELAY)
261 262
		},
		'files.watcherExclude': {
263
			'type': 'object',
264
			'default': platform.isWindows /* https://github.com/Microsoft/vscode/issues/23954 */ ? { '**/.git/objects/**': true, '**/.git/subtree-cache/**': true, '**/node_modules/*/**': true } : { '**/.git/objects/**': true, '**/.git/subtree-cache/**': true, '**/node_modules/**': true },
265
			'description': nls.localize('watcherExclude', "Configure glob patterns of file paths to exclude from file watching. Changing this setting requires a restart. When you experience Code consuming lots of cpu time on startup, you can exclude large folders to reduce the initial load.")
D
Daniel Imms 已提交
266 267
		},
		'files.hotExit': {
268
			'type': 'string',
D
Daniel Imms 已提交
269 270
			'enum': [HotExitConfiguration.OFF, HotExitConfiguration.ON_EXIT, HotExitConfiguration.ON_EXIT_AND_WINDOW_CLOSE],
			'default': HotExitConfiguration.ON_EXIT,
D
Daniel Imms 已提交
271 272
			'enumDescriptions': [
				nls.localize('hotExit.off', 'Disable hot exit.'),
B
Benjamin Pasero 已提交
273 274
				nls.localize('hotExit.onExit', 'Hot exit will be triggered when the application is closed, that is when the last window is closed on Windows/Linux or when the workbench.action.quit command is triggered (command palette, keybinding, menu). All windows with backups will be restored upon next launch.'),
				nls.localize('hotExit.onExitAndWindowClose', 'Hot exit will be triggered when the application is closed, that is 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. To restore folder windows as they were before shutdown set "window.reopenFolders" to "all".')
D
Daniel Imms 已提交
275 276
			],
			'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)
277 278 279 280
		},
		'files.defaultLanguage': {
			'type': 'string',
			'description': nls.localize('defaultLanguage', "The default language mode that is assigned to new files.")
281 282 283 284 285 286
		}
	}
});

configurationRegistry.registerConfiguration({
	id: 'editor',
287 288
	order: 5,
	title: nls.localize('editorConfigurationTitle', "Editor"),
289 290
	type: 'object',
	properties: {
291 292 293
		'editor.formatOnSave': {
			'type': 'boolean',
			'default': false,
294 295
			'description': nls.localize('formatOnSave', "Format a file on save. A formatter must be available, the file must not be auto-saved, and editor must not be shutting down."),
			'overridable': true
E
Erich Gamma 已提交
296 297 298 299 300 301
		}
	}
});

configurationRegistry.registerConfiguration({
	'id': 'explorer',
302
	'order': 10,
303
	'title': nls.localize('explorerConfigurationTitle', "File Explorer"),
E
Erich Gamma 已提交
304 305
	'type': 'object',
	'properties': {
306
		'explorer.openEditors.visible': {
E
Erich Gamma 已提交
307
			'type': 'number',
I
isidor 已提交
308
			'description': nls.localize({ key: 'openEditorsVisible', comment: ['Open is an adjective'] }, "Number of editors shown in the Open Editors pane. Set it to 0 to hide the pane."),
E
Erich Gamma 已提交
309 310
			'default': 9
		},
311
		'explorer.openEditors.dynamicHeight': {
E
Erich Gamma 已提交
312
			'type': 'boolean',
I
isidor 已提交
313
			'description': nls.localize({ key: 'dynamicHeight', comment: ['Open is an adjective'] }, "Controls if the height of the open editors section should adapt dynamically to the number of elements or not."),
E
Erich Gamma 已提交
314
			'default': true
315 316 317
		},
		'explorer.autoReveal': {
			'type': 'boolean',
318
			'description': nls.localize('autoReveal', "Controls if the explorer should automatically reveal and select files when opening them."),
319
			'default': true
320 321 322 323 324
		},
		'explorer.enableDragAndDrop': {
			'type': 'boolean',
			'description': nls.localize('enableDragAndDrop', "Controls if the explorer should allow to move files and folders via drag and drop."),
			'default': true
E
Erich Gamma 已提交
325 326
		}
	}
327
});