files.ts 9.3 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';
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';
E
Erich Gamma 已提交
26 27 28 29 30

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

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

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

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

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

68 69 70
/**
 * Context Keys to use with keybindings for the Explorer and Open Editors view
 */
I
isidor 已提交
71 72 73
export const ExplorerViewletVisibleContext = new RawContextKey<boolean>('explorerViewletVisible', true);
export const ExplorerFolderContext = new RawContextKey<boolean>('explorerResourceIsFolder', false);
export const ExplorerResourceReadonlyContext = new RawContextKey<boolean>('explorerResourceReadonly', false);
74
export const ExplorerResourceNotReadonlyContext = ExplorerResourceReadonlyContext.toNegated();
I
isidor 已提交
75 76
export const ExplorerRootContext = new RawContextKey<boolean>('explorerResourceIsRoot', false);
export const ExplorerResourceCut = new RawContextKey<boolean>('explorerResourceCut', false);
77
export const ExplorerResourceMoveableToTrash = new RawContextKey<boolean>('explorerResourceMoveableToTrash', false);
I
isidor 已提交
78 79 80 81
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 已提交
82

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

I
isidor 已提交
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
/**
 * 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';


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

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

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

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

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

	constructor(
138 139 140 141
		@ITextFileService private readonly textFileService: ITextFileService,
		@IFileService private readonly fileService: IFileService,
		@IModeService private readonly modeService: IModeService,
		@IModelService private readonly modelService: IModelService
142 143 144
	) {
	}

J
Johannes Rieken 已提交
145
	provideTextContent(resource: URI): Promise<ITextModel> {
146
		const fileOnDiskResource = resource.with({ scheme: Schemas.file });
147 148 149 150 151

		// 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 已提交
152 153
			if (!this.fileWatcherDisposable) {
				this.fileWatcherDisposable = this.fileService.onFileChanges(changes => {
154
					if (changes.contains(fileOnDiskResource, FileChangeType.UPDATED)) {
155
						this.resolveEditorModel(resource, false /* do not create if missing */); // update model when resource changes
156 157 158
					}
				});

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

			return codeEditorModel;
		});
	}

J
Johannes Rieken 已提交
171 172 173
	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 已提交
174
		const fileOnDiskResource = resource.with({ scheme: Schemas.file });
175 176 177 178 179 180 181 182

		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 已提交
183
				let languageSelector: ILanguageSelection;
184
				if (fileOnDiskModel) {
A
Alex Dima 已提交
185
					languageSelector = this.modeService.create(fileOnDiskModel.getModeId());
186
				} else {
A
Alex Dima 已提交
187
					languageSelector = this.modeService.createByFilepathOrFirstLine(fileOnDiskResource.fsPath);
188 189
				}

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

			return codeEditorModel;
		});
	}

B
Benjamin Pasero 已提交
197
	dispose(): void {
B
Benjamin Pasero 已提交
198 199
		dispose(this.fileWatcherDisposable);
		this.fileWatcherDisposable = undefined;
200
	}
201
}
I
isidor 已提交
202 203 204 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 237 238 239 240 241 242 243 244

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 });
	}
}