files.ts 9.7 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
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
27
import { toLocalResource } from 'vs/base/common/resources';
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 65

	/**
	 * Selects and reveal the file element provided by the given resource if its found in the explorer. Will try to
	 * resolve the path from the disk in case the explorer is not yet expanded to the file yet.
	 */
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 136
export type SortOrder = 'default' | 'mixed' | 'filesFirst' | 'type' | 'modified';

export class FileOnDiskContentProvider 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 144
		@IModelService private readonly modelService: IModelService,
		@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService
145 146 147
	) {
	}

J
Johannes Rieken 已提交
148
	provideTextContent(resource: URI): Promise<ITextModel> {
149
		const savedFileResource = toLocalResource(resource, this.environmentService.configuration.remoteAuthority);
150 151 152 153 154

		// Make sure our file from disk is resolved up to date
		return this.resolveEditorModel(resource).then(codeEditorModel => {

			// Make sure to keep contents on disk up to date when it changes
B
Benjamin Pasero 已提交
155 156
			if (!this.fileWatcherDisposable) {
				this.fileWatcherDisposable = this.fileService.onFileChanges(changes => {
157
					if (changes.contains(savedFileResource, FileChangeType.UPDATED)) {
158
						this.resolveEditorModel(resource, false /* do not create if missing */); // update model when resource changes
159 160 161
					}
				});

M
Matt Bierner 已提交
162
				if (codeEditorModel) {
B
Benjamin Pasero 已提交
163 164 165
					once(codeEditorModel.onWillDispose)(() => {
						dispose(this.fileWatcherDisposable);
						this.fileWatcherDisposable = undefined;
M
Matt Bierner 已提交
166 167
					});
				}
168 169 170 171 172 173
			}

			return codeEditorModel;
		});
	}

J
Johannes Rieken 已提交
174 175 176
	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> {
177
		const savedFileResource = toLocalResource(resource, this.environmentService.configuration.remoteAuthority);
178

179
		return this.textFileService.readStream(savedFileResource).then(content => {
180 181 182 183
			let codeEditorModel = this.modelService.getModel(resource);
			if (codeEditorModel) {
				this.modelService.updateModel(codeEditorModel, content.value);
			} else if (createAsNeeded) {
184
				const fileOnDiskModel = this.modelService.getModel(savedFileResource);
185

A
Alex Dima 已提交
186
				let languageSelector: ILanguageSelection;
187
				if (fileOnDiskModel) {
A
Alex Dima 已提交
188
					languageSelector = this.modeService.create(fileOnDiskModel.getModeId());
189
				} else {
190
					languageSelector = this.modeService.createByFilepathOrFirstLine(savedFileResource.fsPath);
191 192
				}

A
Alex Dima 已提交
193
				codeEditorModel = this.modelService.createModel(content.value, languageSelector, resource);
194 195 196 197 198 199
			}

			return codeEditorModel;
		});
	}

B
Benjamin Pasero 已提交
200
	dispose(): void {
B
Benjamin Pasero 已提交
201 202
		dispose(this.fileWatcherDisposable);
		this.fileWatcherDisposable = undefined;
203
	}
204
}
I
isidor 已提交
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236

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 {
237
		return !!toResource(this.editor, { supportSideBySide: SideBySideEditor.MASTER, filterByScheme: Schemas.untitled });
I
isidor 已提交
238 239 240 241 242 243 244
	}

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

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