pathService.ts 3.9 KB
Newer Older
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 7
import { IPath, win32, posix } from 'vs/base/common/path';
import { OperatingSystem, OS } from 'vs/base/common/platform';
8 9 10 11
import { URI } from 'vs/base/common/uri';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';

12
export const IPathService = createDecorator<IPathService>('path');
13

14 15 16 17 18 19
/**
 * Provides access to path related properties that will match the
 * environment. If the environment is connected to a remote, the
 * path properties will match that of the remotes operating system.
 */
export interface IPathService {
B
Benjamin Pasero 已提交
20

21
	readonly _serviceBrand: undefined;
22

B
Benjamin Pasero 已提交
23
	/**
24 25 26 27
	 * The correct path library to use for the target environment. If
	 * the environment is connected to a remote, this will be the
	 * path library of the remote file system. Otherwise it will be
	 * the local file system's path library depending on the OS.
B
Benjamin Pasero 已提交
28
	 */
29
	readonly path: Promise<IPath>;
B
Benjamin Pasero 已提交
30 31

	/**
32 33 34 35 36
	 * Converts the given path to a file URI to use for the target
	 * environment. If the environment is connected to a remote, it
	 * will use the path separators according to the remote file
	 * system. Otherwise it will use the local file system's path
	 * separators.
B
Benjamin Pasero 已提交
37
	 */
38
	fileURI(path: string): Promise<URI>;
39

B
Benjamin Pasero 已提交
40
	/**
41 42
	 * Resolves the user-home directory for the target environment.
	 * If the envrionment is connected to a remote, this will be the
43 44
	 * remote's user home directory, otherwise the local one unless
	 * `preferLocal` is set to `true`.
B
Benjamin Pasero 已提交
45
	 */
46
	userHome(options?: { preferLocal: boolean }): Promise<URI>;
B
Benjamin Pasero 已提交
47 48

	/**
49
	 * @deprecated use `userHome` instead.
B
Benjamin Pasero 已提交
50
	 */
51
	readonly resolvedUserHome: URI | undefined;
52 53
}

54
export abstract class AbstractPathService implements IPathService {
55

56
	declare readonly _serviceBrand: undefined;
57

58
	private resolveOS: Promise<OperatingSystem>;
59 60 61

	private resolveUserHome: Promise<URI>;
	private maybeUnresolvedUserHome: URI | undefined;
62 63

	constructor(
64
		private localUserHome: URI,
65
		@IRemoteAgentService private readonly remoteAgentService: IRemoteAgentService
66
	) {
67

68 69 70 71 72 73 74 75 76 77 78 79
		// OS
		this.resolveOS = (async () => {
			const env = await this.remoteAgentService.getEnvironment();

			return env?.os || OS;
		})();

		// User Home
		this.resolveUserHome = (async () => {
			const env = await this.remoteAgentService.getEnvironment();
			const userHome = this.maybeUnresolvedUserHome = env?.userHome || localUserHome;

B
Benjamin Pasero 已提交
80

81
			return userHome;
82
		})();
83 84
	}

85 86
	async userHome(options?: { preferLocal: boolean }): Promise<URI> {
		return options?.preferLocal ? this.localUserHome : this.resolveUserHome;
87 88 89 90 91 92 93
	}

	get resolvedUserHome(): URI | undefined {
		return this.maybeUnresolvedUserHome;
	}

	get path(): Promise<IPath> {
94
		return this.resolveOS.then(os => {
95 96 97
			return os === OperatingSystem.Windows ?
				win32 :
				posix;
98 99 100 101 102 103 104 105 106
		});
	}

	async fileURI(_path: string): Promise<URI> {
		let authority = '';

		// normalize to fwd-slashes on windows,
		// on other systems bwd-slashes are valid
		// filename character, eg /f\oo/ba\r.txt
107 108
		const os = await this.resolveOS;
		if (os === OperatingSystem.Windows) {
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
			_path = _path.replace(/\\/g, '/');
		}

		// check for authority as used in UNC shares
		// or use the path as given
		if (_path[0] === '/' && _path[1] === '/') {
			const idx = _path.indexOf('/', 2);
			if (idx === -1) {
				authority = _path.substring(2);
				_path = '/';
			} else {
				authority = _path.substring(2, idx);
				_path = _path.substring(idx) || '/';
			}
		}

		// return new _URI('file', authority, path, '', '');
		return URI.from({
			scheme: 'file',
			authority,
			path: _path,
			query: '',
			fragment: ''
		});
	}
}