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

6
import { URI } from 'vs/base/common/uri';
7
import { IEditorOptions } from 'vs/editor/common/config/editorOptions';
B
Benjamin Pasero 已提交
8
import { IWorkbenchEditorConfiguration, IEditorIdentifier, IEditorInput, toResource, SideBySideEditor } from 'vs/workbench/common/editor';
9
import { IFilesConfiguration, FileChangeType, IFileService } from 'vs/platform/files/common/files';
B
Benjamin Pasero 已提交
10
import { ContextKeyExpr, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
11
import { ITextModelContentProvider } from 'vs/editor/common/services/resolverService';
12
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
A
Alex Dima 已提交
13
import { ITextModel } from 'vs/editor/common/model';
I
isidor 已提交
14
import { Event } from 'vs/base/common/event';
15
import { IModelService } from 'vs/editor/common/services/modelService';
A
Alex Dima 已提交
16
import { IModeService, ILanguageSelection } from 'vs/editor/common/services/modeService';
17
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
18
import { InputFocusedContextKey } from 'vs/platform/contextkey/common/contextkeys';
S
Sandeep Somavarapu 已提交
19 20
import { Registry } from 'vs/platform/registry/common/platform';
import { IViewContainersRegistry, Extensions as ViewContainerExtensions, ViewContainer } from 'vs/workbench/common/views';
21
import { Schemas } from 'vs/base/common/network';
I
isidor 已提交
22
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
23
import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService';
24
import { ExplorerItem } from 'vs/workbench/contrib/files/common/explorerModel';
B
Benjamin Pasero 已提交
25
import { once } from 'vs/base/common/functional';
26 27
import { ITextEditorOptions } from 'vs/platform/editor/common/editor';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
E
Erich Gamma 已提交
28 29 30 31 32

/**
 * Explorer viewlet id.
 */
export const VIEWLET_ID = 'workbench.view.explorer';
S
Sandeep Somavarapu 已提交
33 34 35 36
/**
 * Explorer viewlet container.
 */
export const VIEW_CONTAINER: ViewContainer = Registry.as<IViewContainersRegistry>(ViewContainerExtensions.ViewContainersRegistry).registerViewContainer(VIEWLET_ID);
E
Erich Gamma 已提交
37

38
export interface IEditableData {
M
Matt Bierner 已提交
39
	validationMessage: (value: string) => string | null;
40
	onFinish: (value: string, success: boolean) => void;
41 42
}

I
isidor 已提交
43 44 45
export interface IExplorerService {
	_serviceBrand: any;
	readonly roots: ExplorerItem[];
I
isidor 已提交
46
	readonly sortOrder: SortOrder;
I
isidor 已提交
47
	readonly onDidChangeRoots: Event<void>;
48
	readonly onDidChangeItem: Event<{ item?: ExplorerItem, recursive: boolean }>;
49
	readonly onDidChangeEditable: Event<ExplorerItem>;
I
isidor 已提交
50
	readonly onDidSelectResource: Event<{ resource?: URI, reveal?: boolean }>;
I
isidor 已提交
51
	readonly onDidCopyItems: Event<{ items: ExplorerItem[], cut: boolean, previouslyCutItems: ExplorerItem[] | undefined }>;
I
isidor 已提交
52

M
Matt Bierner 已提交
53
	setEditable(stat: ExplorerItem, data: IEditableData | null): void;
54
	getEditableData(stat: ExplorerItem): IEditableData | undefined;
I
isidor 已提交
55 56
	// If undefined is passed checks if any element is currently being edited.
	isEditable(stat: ExplorerItem | undefined): boolean;
I
isidor 已提交
57
	findClosest(resource: URI): ExplorerItem | null;
I
isidor 已提交
58
	refresh(): void;
I
isidor 已提交
59 60
	setToCopy(stats: ExplorerItem[], cut: boolean): void;
	isCut(stat: ExplorerItem): boolean;
I
isidor 已提交
61 62

	/**
63 64
	 * Selects and reveal the file element provided by the given resource if its found in the explorer.
	 * Will try to resolve the path in case the explorer is not yet expanded to the file yet.
I
isidor 已提交
65
	 */
66
	select(resource: URI, reveal?: boolean): Promise<void>;
I
isidor 已提交
67 68 69
}
export const IExplorerService = createDecorator<IExplorerService>('explorerService');

70 71 72
/**
 * Context Keys to use with keybindings for the Explorer and Open Editors view
 */
I
isidor 已提交
73 74 75
export const ExplorerViewletVisibleContext = new RawContextKey<boolean>('explorerViewletVisible', true);
export const ExplorerFolderContext = new RawContextKey<boolean>('explorerResourceIsFolder', false);
export const ExplorerResourceReadonlyContext = new RawContextKey<boolean>('explorerResourceReadonly', false);
76
export const ExplorerResourceNotReadonlyContext = ExplorerResourceReadonlyContext.toNegated();
I
isidor 已提交
77 78
export const ExplorerRootContext = new RawContextKey<boolean>('explorerResourceIsRoot', false);
export const ExplorerResourceCut = new RawContextKey<boolean>('explorerResourceCut', false);
79
export const ExplorerResourceMoveableToTrash = new RawContextKey<boolean>('explorerResourceMoveableToTrash', false);
I
isidor 已提交
80 81 82 83
export const FilesExplorerFocusedContext = new RawContextKey<boolean>('filesExplorerFocus', true);
export const OpenEditorsVisibleContext = new RawContextKey<boolean>('openEditorsVisible', false);
export const OpenEditorsFocusedContext = new RawContextKey<boolean>('openEditorsFocus', true);
export const ExplorerFocusedContext = new RawContextKey<boolean>('explorerViewletFocus', true);
B
Benjamin Pasero 已提交
84

I
isidor 已提交
85 86
export const FilesExplorerFocusCondition = ContextKeyExpr.and(ExplorerViewletVisibleContext, FilesExplorerFocusedContext, ContextKeyExpr.not(InputFocusedContextKey));
export const ExplorerFocusCondition = ContextKeyExpr.and(ExplorerViewletVisibleContext, ExplorerFocusedContext, ContextKeyExpr.not(InputFocusedContextKey));
A
Alex Dima 已提交
87

I
isidor 已提交
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
/**
 * Text file editor id.
 */
export const TEXT_FILE_EDITOR_ID = 'workbench.editors.files.textFileEditor';

/**
 * File editor input id.
 */
export const FILE_EDITOR_INPUT_ID = 'workbench.editors.files.fileEditorInput';

/**
 * Binary file editor id.
 */
export const BINARY_FILE_EDITOR_ID = 'workbench.editors.files.binaryFileEditor';


104
export interface IFilesConfiguration extends IFilesConfiguration, IWorkbenchEditorConfiguration {
E
Erich Gamma 已提交
105
	explorer: {
I
isidor 已提交
106
		openEditors: {
107
			visible: number;
E
Erich Gamma 已提交
108
		};
109
		autoReveal: boolean;
110
		enableDragAndDrop: boolean;
111
		confirmDelete: boolean;
112
		sortOrder: SortOrder;
113 114 115
		decorations: {
			colors: boolean;
			badges: boolean;
J
Johannes Rieken 已提交
116
		};
E
Erich Gamma 已提交
117 118 119 120 121 122
	};
	editor: IEditorOptions;
}

export interface IFileResource {
	resource: URI;
123
	isDirectory?: boolean;
E
Erich Gamma 已提交
124 125
}

126 127 128 129 130 131 132 133
export const SortOrderConfiguration = {
	DEFAULT: 'default',
	MIXED: 'mixed',
	FILES_FIRST: 'filesFirst',
	TYPE: 'type',
	MODIFIED: 'modified'
};

134 135
export type SortOrder = 'default' | 'mixed' | 'filesFirst' | 'type' | 'modified';

136
export class TextFileContentProvider implements ITextModelContentProvider {
B
Benjamin Pasero 已提交
137
	private fileWatcherDisposable: IDisposable | undefined;
138 139

	constructor(
140 141 142
		@ITextFileService private readonly textFileService: ITextFileService,
		@IFileService private readonly fileService: IFileService,
		@IModeService private readonly modeService: IModeService,
143
		@IModelService private readonly modelService: IModelService
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
	) { }

	static open(resource: URI, scheme: string, label: string, editorService: IEditorService, options?: ITextEditorOptions): Promise<void> {
		return editorService.openEditor(
			{
				leftResource: TextFileContentProvider.resourceToTextFile(scheme, resource),
				rightResource: resource,
				label,
				options
			}
		).then();
	}

	private static resourceToTextFile(scheme: string, resource: URI): URI {
		return resource.with({ scheme, query: JSON.stringify({ scheme: resource.scheme }) });
	}

	private static textFileToResource(resource: URI): URI {
		return resource.with({ scheme: JSON.parse(resource.query)['scheme'], query: null });
163 164
	}

J
Johannes Rieken 已提交
165
	provideTextContent(resource: URI): Promise<ITextModel> {
166
		const savedFileResource = TextFileContentProvider.textFileToResource(resource);
167

168
		// Make sure our text file is resolved up to date
169 170
		return this.resolveEditorModel(resource).then(codeEditorModel => {

171
			// Make sure to keep contents up to date when it changes
B
Benjamin Pasero 已提交
172 173
			if (!this.fileWatcherDisposable) {
				this.fileWatcherDisposable = this.fileService.onFileChanges(changes => {
174
					if (changes.contains(savedFileResource, FileChangeType.UPDATED)) {
175
						this.resolveEditorModel(resource, false /* do not create if missing */); // update model when resource changes
176 177 178
					}
				});

M
Matt Bierner 已提交
179
				if (codeEditorModel) {
B
Benjamin Pasero 已提交
180 181 182
					once(codeEditorModel.onWillDispose)(() => {
						dispose(this.fileWatcherDisposable);
						this.fileWatcherDisposable = undefined;
M
Matt Bierner 已提交
183 184
					});
				}
185 186 187 188 189 190
			}

			return codeEditorModel;
		});
	}

J
Johannes Rieken 已提交
191 192 193
	private resolveEditorModel(resource: URI, createAsNeeded?: true): Promise<ITextModel>;
	private resolveEditorModel(resource: URI, createAsNeeded?: boolean): Promise<ITextModel | null>;
	private resolveEditorModel(resource: URI, createAsNeeded: boolean = true): Promise<ITextModel | null> {
194
		const savedFileResource = TextFileContentProvider.textFileToResource(resource);
195

196
		return this.textFileService.readStream(savedFileResource).then(content => {
197 198 199 200
			let codeEditorModel = this.modelService.getModel(resource);
			if (codeEditorModel) {
				this.modelService.updateModel(codeEditorModel, content.value);
			} else if (createAsNeeded) {
201
				const textFileModel = this.modelService.getModel(savedFileResource);
202

A
Alex Dima 已提交
203
				let languageSelector: ILanguageSelection;
204 205
				if (textFileModel) {
					languageSelector = this.modeService.create(textFileModel.getModeId());
206
				} else {
B
Benjamin Pasero 已提交
207
					languageSelector = this.modeService.createByFilepathOrFirstLine(savedFileResource.path);
208 209
				}

A
Alex Dima 已提交
210
				codeEditorModel = this.modelService.createModel(content.value, languageSelector, resource);
211 212 213 214 215 216
			}

			return codeEditorModel;
		});
	}

B
Benjamin Pasero 已提交
217
	dispose(): void {
B
Benjamin Pasero 已提交
218 219
		dispose(this.fileWatcherDisposable);
		this.fileWatcherDisposable = undefined;
220
	}
221
}
I
isidor 已提交
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253

export class OpenEditor implements IEditorIdentifier {

	constructor(private _editor: IEditorInput, private _group: IEditorGroup) {
		// noop
	}

	public get editor() {
		return this._editor;
	}

	public get editorIndex() {
		return this._group.getIndexOfEditor(this.editor);
	}

	public get group() {
		return this._group;
	}

	public get groupId() {
		return this._group.id;
	}

	public getId(): string {
		return `openeditor:${this.groupId}:${this.editorIndex}:${this.editor.getName()}:${this.editor.getDescription()}`;
	}

	public isPreview(): boolean {
		return this._group.previewEditor === this.editor;
	}

	public isUntitled(): boolean {
254
		return !!toResource(this.editor, { supportSideBySide: SideBySideEditor.MASTER, filterByScheme: Schemas.untitled });
I
isidor 已提交
255 256 257 258 259 260 261
	}

	public isDirty(): boolean {
		return this.editor.isDirty();
	}

	public getResource(): URI | null {
B
Benjamin Pasero 已提交
262
		return toResource(this.editor, { supportSideBySide: SideBySideEditor.MASTER });
I
isidor 已提交
263 264
	}
}