Skip to content

Commit

Permalink
Path conversion for windows and posix file systems
Browse files Browse the repository at this point in the history
  • Loading branch information
msujew committed Jan 4, 2022
1 parent 17b419f commit da93ba2
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 4 deletions.
13 changes: 10 additions & 3 deletions packages/core/src/browser/resource-context-key.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import URI from '../common/uri';
import { URI as Uri } from 'vscode-uri';
import { ContextKeyService, ContextKey } from './context-key-service';
import { LanguageService } from './language-service';
import { ApplicationServer } from '../common/application-protocol';
import { OS } from '../common/os';

@injectable()
export class ResourceContextKey {
Expand All @@ -29,23 +31,28 @@ export class ResourceContextKey {
@inject(ContextKeyService)
protected readonly contextKeyService: ContextKeyService;

@inject(ApplicationServer)
protected readonly applicationService: ApplicationServer;

protected resource: ContextKey<Uri>;
protected resourceSchemeKey: ContextKey<string>;
protected resourceFileName: ContextKey<string>;
protected resourceExtname: ContextKey<string>;
protected resourceLangId: ContextKey<string>;
protected resourceDirName: ContextKey<string>;
protected resourcePath: ContextKey<string>;
protected isPosix: boolean;

@postConstruct()
protected init(): void {
protected async init(): Promise<void> {
this.resource = this.contextKeyService.createKey<Uri>('resource', undefined);
this.resourceSchemeKey = this.contextKeyService.createKey<string>('resourceScheme', undefined);
this.resourceFileName = this.contextKeyService.createKey<string>('resourceFilename', undefined);
this.resourceExtname = this.contextKeyService.createKey<string>('resourceExtname', undefined);
this.resourceLangId = this.contextKeyService.createKey<string>('resourceLangId', undefined);
this.resourceDirName = this.contextKeyService.createKey<string>('resourceDirName', undefined);
this.resourcePath = this.contextKeyService.createKey<string>('resourcePath', undefined);
this.isPosix = await this.applicationService.getBackendOS() !== OS.Type.Windows;
}

get(): URI | undefined {
Expand All @@ -59,8 +66,8 @@ export class ResourceContextKey {
this.resourceFileName.set(resourceUri && resourceUri.path.base);
this.resourceExtname.set(resourceUri && resourceUri.path.ext);
this.resourceLangId.set(resourceUri && this.getLanguageId(resourceUri));
this.resourceDirName.set(resourceUri && Uri.parse(resourceUri.path.dir.toString()).fsPath);
this.resourcePath.set(resourceUri && resourceUri['codeUri'].fsPath);
this.resourceDirName.set(resourceUri && resourceUri.path.dir.fsPath(this.isPosix));
this.resourcePath.set(resourceUri && resourceUri.path.fsPath(this.isPosix));
}

protected getLanguageId(uri: URI | undefined): string | undefined {
Expand Down
56 changes: 56 additions & 0 deletions packages/core/src/common/path.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -356,4 +356,60 @@ describe('Path', () => {
});

});

describe('fsPath#undefined', () => {
it('should retain windows style path', () => {
const path = 'C:\\path\\to\\file.txt';
expect(new Path(path).fsPath()).eq(path);
});

it('should create windows style path with slashes', () => {
const path = 'C:/path/to/file.txt';
const expected = 'C:\\path\\to\\file.txt';
expect(new Path(path).fsPath()).eq(expected);
});

it('should retain posix style path', () => {
const path = '/path/to/file.txt';
expect(new Path(path).fsPath()).eq(path);
});
});

describe('fsPath#windows', () => {
it('should retain windows style path', () => {
const path = 'C:\\path\\to\\file.txt';
expect(new Path(path).fsPath(false)).eq(path);
});

it('should create windows style path with slashes', () => {
const path = 'C:/path/to/file.txt';
const expected = 'C:\\path\\to\\file.txt';
expect(new Path(path).fsPath(false)).eq(expected);
});

it('should create windows style path from posix', () => {
const path = '/path/to/file.txt';
const expected = '\\path\\to\\file.txt';
expect(new Path(path).fsPath(false)).eq(expected);
});
});

describe('fsPath#posix', () => {
it('should retain posix style path', () => {
const path = '/path/to/file.txt';
expect(new Path(path).fsPath(true)).eq(path);
});

it('should create posix style path from windows with slashes', () => {
const path = 'C:/path/to/file.txt';
const expected = '/c:/path/to/file.txt';
expect(new Path(path).fsPath(true)).eq(expected);
});

it('should create posix style path from windows', () => {
const path = 'C:\\path\\to\\file.txt';
const expected = '/c:/path/to/file.txt';
expect(new Path(path).fsPath(true)).eq(expected);
});
});
});
49 changes: 49 additions & 0 deletions packages/core/src/common/path.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,35 @@ export class Path {
return path.split(/[\\]/).join(Path.separator);
}

/**
* Creates a windows path from the given path string.
* A windows path uses an upper case drive letter and backwards slashes.
* @param path The input path
* @returns Windows style path
*/
static windowsPath(path: string): string {
const offset = path.charAt(0) === '/' ? 1 : 0;
if (path.charAt(offset + 2) === '/' && path.charAt(offset + 1) === ':') {
const driveLetter = path.charAt(offset).toUpperCase();
const substring = path.substring(offset + 1).replace(/\//g, '\\');
return `${driveLetter}${substring}`;
}
return path.replace(/\//g, '\\');
}

/**
* Creates a posix path from the given path string.
* A posix path always starts with a forward slash and contains only forward slashes.
* @param path The input path
* @returns A posix style path
*/
static posixPath(path: string): string {
if (path.charAt(0) !== '/') {
path = '/' + path;
}
return path;
}

/**
* Tildify path, replacing `home` with `~` if user's `home` is present at the beginning of the path.
* This is a non-operation for Windows.
Expand Down Expand Up @@ -206,6 +235,26 @@ export class Path {
return this.raw;
}

/**
* Converts the current path into a file system path.
* @param posix Indicates posix or windows file path.
* If `undefined`, the format will be determined by whether the raw path starts with a drive letter.
* @returns A file system path.
*/
fsPath(posix?: boolean): string {
if (posix === undefined) {
if (this.raw.charAt(1) === ':' || this.raw.charAt(2) === ':') {
return Path.windowsPath(this.raw);
} else {
return Path.posixPath(this.raw);
}
} else if (posix) {
return Path.posixPath(this.raw);
} else {
return Path.windowsPath(this.raw);
}
}

relative(path: Path): Path | undefined {
if (this.raw === path.raw) {
return new Path('');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ export class FileTreeWidget extends TreeViewWelcomeWidget {

protected getNodeTooltip(node: TreeNode): string | undefined {
const uri = UriSelection.getUri(node);
return uri ? uri.path.toString() : undefined;
return uri ? uri.path.fsPath() : undefined;
}

protected handleDragStartEvent(node: TreeNode, event: React.DragEvent): void {
Expand Down

0 comments on commit da93ba2

Please sign in to comment.