files.ts 9.6 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';
I
isidor 已提交
8
import { IWorkbenchEditorConfiguration, IEditorIdentifier, IEditorInput, toResource } 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';
J
Joao Moreno 已提交
18
import { InputFocusedContextKey } from 'vs/platform/workbench/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 23
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IEditorGroup } from 'vs/workbench/services/group/common/editorGroupsService';
24
import { ExplorerItem } from 'vs/workbench/contrib/files/common/explorerModel';
E
Erich Gamma 已提交
25 26 27 28 29

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

35 36
export interface IEditableData {
	validationMessage: (value: string) => string;
37
	onFinish: (value: string, success: boolean) => void;
38 39
}

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

50 51
	setEditable(stat: ExplorerItem, data: IEditableData): void;
	getEditableData(stat: ExplorerItem): IEditableData | undefined;
52
	isEditable(stat: ExplorerItem): boolean;
I
isidor 已提交
53
	findClosest(resource: URI): ExplorerItem | null;
I
isidor 已提交
54
	refresh(): void;
I
isidor 已提交
55 56
	setToCopy(stats: ExplorerItem[], cut: boolean): void;
	isCut(stat: ExplorerItem): boolean;
I
isidor 已提交
57 58 59 60 61

	/**
	 * 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.
	 */
62
	select(resource: URI, reveal?: boolean): Promise<void>;
I
isidor 已提交
63 64 65
}
export const IExplorerService = createDecorator<IExplorerService>('explorerService');

66 67 68
/**
 * Context Keys to use with keybindings for the Explorer and Open Editors view
 */
B
Benjamin Pasero 已提交
69 70
const explorerViewletVisibleId = 'explorerViewletVisible';
const filesExplorerFocusId = 'filesExplorerFocus';
I
isidor 已提交
71
const openEditorsVisibleId = 'openEditorsVisible';
B
Benjamin Pasero 已提交
72 73 74
const openEditorsFocusId = 'openEditorsFocus';
const explorerViewletFocusId = 'explorerViewletFocus';
const explorerResourceIsFolderId = 'explorerResourceIsFolder';
75
const explorerResourceReadonly = 'explorerResourceReadonly';
76
const explorerResourceIsRootId = 'explorerResourceIsRoot';
77
const explorerResourceCutId = 'explorerResourceCut';
B
Benjamin Pasero 已提交
78 79 80

export const ExplorerViewletVisibleContext = new RawContextKey<boolean>(explorerViewletVisibleId, true);
export const ExplorerFolderContext = new RawContextKey<boolean>(explorerResourceIsFolderId, false);
81 82
export const ExplorerResourceReadonlyContext = new RawContextKey<boolean>(explorerResourceReadonly, false);
export const ExplorerResourceNotReadonlyContext = ExplorerResourceReadonlyContext.toNegated();
83
export const ExplorerRootContext = new RawContextKey<boolean>(explorerResourceIsRootId, false);
84
export const ExplorerResourceCut = new RawContextKey<boolean>(explorerResourceCutId, false);
J
Joao Moreno 已提交
85
export const FilesExplorerFocusedContext = new RawContextKey<boolean>(filesExplorerFocusId, true);
I
isidor 已提交
86
export const OpenEditorsVisibleContext = new RawContextKey<boolean>(openEditorsVisibleId, false);
J
Joao Moreno 已提交
87 88
export const OpenEditorsFocusedContext = new RawContextKey<boolean>(openEditorsFocusId, true);
export const ExplorerFocusedContext = new RawContextKey<boolean>(explorerViewletFocusId, true);
B
Benjamin Pasero 已提交
89

I
isidor 已提交
90
export const OpenEditorsVisibleCondition = ContextKeyExpr.has(openEditorsVisibleId);
J
Joao Moreno 已提交
91 92
export const FilesExplorerFocusCondition = ContextKeyExpr.and(ContextKeyExpr.has(explorerViewletVisibleId), ContextKeyExpr.has(filesExplorerFocusId), ContextKeyExpr.not(InputFocusedContextKey));
export const ExplorerFocusCondition = ContextKeyExpr.and(ContextKeyExpr.has(explorerViewletVisibleId), ContextKeyExpr.has(explorerViewletFocusId), ContextKeyExpr.not(InputFocusedContextKey));
A
Alex Dima 已提交
93

I
isidor 已提交
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
/**
 * 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';


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

export interface IFileResource {
	resource: URI;
129
	isDirectory?: boolean;
E
Erich Gamma 已提交
130 131
}

132 133 134 135 136 137 138 139
export const SortOrderConfiguration = {
	DEFAULT: 'default',
	MIXED: 'mixed',
	FILES_FIRST: 'filesFirst',
	TYPE: 'type',
	MODIFIED: 'modified'
};

140 141 142 143 144 145
export type SortOrder = 'default' | 'mixed' | 'filesFirst' | 'type' | 'modified';

export class FileOnDiskContentProvider implements ITextModelContentProvider {
	private fileWatcher: IDisposable;

	constructor(
146 147 148 149
		@ITextFileService private readonly textFileService: ITextFileService,
		@IFileService private readonly fileService: IFileService,
		@IModeService private readonly modeService: IModeService,
		@IModelService private readonly modelService: IModelService
150 151 152
	) {
	}

J
Johannes Rieken 已提交
153
	provideTextContent(resource: URI): Promise<ITextModel> {
154
		const fileOnDiskResource = resource.with({ scheme: Schemas.file });
155 156 157 158 159 160 161

		// 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
			if (!this.fileWatcher) {
				this.fileWatcher = this.fileService.onFileChanges(changes => {
162
					if (changes.contains(fileOnDiskResource, FileChangeType.UPDATED)) {
163
						this.resolveEditorModel(resource, false /* do not create if missing */); // update model when resource changes
164 165 166
					}
				});

M
Matt Bierner 已提交
167 168 169 170 171 172
				if (codeEditorModel) {
					const disposeListener = codeEditorModel.onWillDispose(() => {
						disposeListener.dispose();
						this.fileWatcher = dispose(this.fileWatcher);
					});
				}
173 174 175 176 177 178
			}

			return codeEditorModel;
		});
	}

J
Johannes Rieken 已提交
179 180 181
	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> {
I
isidor 已提交
182
		const fileOnDiskResource = resource.with({ scheme: Schemas.file });
183 184 185 186 187 188 189 190

		return this.textFileService.resolveTextContent(fileOnDiskResource).then(content => {
			let codeEditorModel = this.modelService.getModel(resource);
			if (codeEditorModel) {
				this.modelService.updateModel(codeEditorModel, content.value);
			} else if (createAsNeeded) {
				const fileOnDiskModel = this.modelService.getModel(fileOnDiskResource);

A
Alex Dima 已提交
191
				let languageSelector: ILanguageSelection;
192
				if (fileOnDiskModel) {
A
Alex Dima 已提交
193
					languageSelector = this.modeService.create(fileOnDiskModel.getModeId());
194
				} else {
A
Alex Dima 已提交
195
					languageSelector = this.modeService.createByFilepathOrFirstLine(fileOnDiskResource.fsPath);
196 197
				}

A
Alex Dima 已提交
198
				codeEditorModel = this.modelService.createModel(content.value, languageSelector, resource);
199 200 201 202 203 204
			}

			return codeEditorModel;
		});
	}

B
Benjamin Pasero 已提交
205
	dispose(): void {
206
		this.fileWatcher = dispose(this.fileWatcher);
207
	}
208
}
I
isidor 已提交
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 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251

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 {
		return !!toResource(this.editor, { supportSideBySide: true, filter: Schemas.untitled });
	}

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

	public getResource(): URI | null {
		return toResource(this.editor, { supportSideBySide: true });
	}
}