diff --git a/src/annotations/fileAnnotationController.ts b/src/annotations/fileAnnotationController.ts index e5fd34f..fecbea7 100644 --- a/src/annotations/fileAnnotationController.ts +++ b/src/annotations/fileAnnotationController.ts @@ -1,5 +1,4 @@ 'use strict'; -import { basename } from 'path'; import { ConfigurationChangeEvent, DecorationRangeBehavior, @@ -30,6 +29,7 @@ import { Container } from '../container'; import { KeyboardScope } from '../keyboard'; import { Logger } from '../logger'; import { Functions, Iterables } from '../system'; +import { basename } from '../system/path'; import { DocumentBlameStateChangeEvent, DocumentDirtyStateChangeEvent, diff --git a/src/commands/browseRepoAtRevision.ts b/src/commands/browseRepoAtRevision.ts index 41b440b..3001882 100644 --- a/src/commands/browseRepoAtRevision.ts +++ b/src/commands/browseRepoAtRevision.ts @@ -1,5 +1,4 @@ 'use strict'; -import { basename } from 'path'; import { commands, TextEditor, Uri } from 'vscode'; import { BuiltInCommands } from '../constants'; import { Container } from '../container'; @@ -7,6 +6,7 @@ import { toGitLensFSUri } from '../git/fsProvider'; import { GitUri } from '../git/gitUri'; import { Logger } from '../logger'; import { Messages } from '../messages'; +import { basename } from '../system/path'; import { ActiveEditorCommand, command, diff --git a/src/commands/common.ts b/src/commands/common.ts index 001e72b..b6a17d1 100644 --- a/src/commands/common.ts +++ b/src/commands/common.ts @@ -1,5 +1,4 @@ 'use strict'; -import { extname } from 'path'; import { commands, Disposable, @@ -32,6 +31,7 @@ import { } from '../git/models'; import { Logger } from '../logger'; import { CommandQuickPickItem, RepositoryPicker } from '../quickpicks'; +import { extname } from '../system/path'; import { ViewNode, ViewRefNode } from '../views/nodes'; export const enum Commands { diff --git a/src/commands/diffWith.ts b/src/commands/diffWith.ts index 298edc6..e7ffdd6 100644 --- a/src/commands/diffWith.ts +++ b/src/commands/diffWith.ts @@ -1,5 +1,4 @@ 'use strict'; -import { basename } from 'path'; import { commands, Range, TextDocumentShowOptions, Uri, ViewColumn } from 'vscode'; import { BuiltInCommands, GlyphChars } from '../constants'; import { Container } from '../container'; @@ -7,6 +6,7 @@ import { GitUri } from '../git/gitUri'; import { GitCommit, GitRevision } from '../git/models'; import { Logger } from '../logger'; import { Messages } from '../messages'; +import { basename } from '../system/path'; import { command, Command, Commands } from './common'; export interface DiffWithCommandArgsRevision { diff --git a/src/commands/diffWithRevisionFrom.ts b/src/commands/diffWithRevisionFrom.ts index 9bda508..da9d2f9 100644 --- a/src/commands/diffWithRevisionFrom.ts +++ b/src/commands/diffWithRevisionFrom.ts @@ -1,5 +1,4 @@ 'use strict'; -import { basename, relative } from 'path'; import { TextDocumentShowOptions, TextEditor, Uri } from 'vscode'; import { GlyphChars, quickPickTitleMaxChars } from '../constants'; import { Container } from '../container'; @@ -8,6 +7,7 @@ import { GitReference, GitRevision } from '../git/models'; import { Messages } from '../messages'; import { ReferencePicker, StashPicker } from '../quickpicks'; import { Strings } from '../system'; +import { basename, normalizePath, relative } from '../system/path'; import { ActiveEditorCommand, command, Commands, executeCommand, getCommandUri } from './common'; import { DiffWithCommandArgs } from './diffWith'; @@ -42,7 +42,7 @@ export class DiffWithRevisionFromCommand extends ActiveEditorCommand { let ref; let sha; if (args?.stash) { - const fileName = Strings.normalizePath(relative(gitUri.repoPath, gitUri.fsPath)); + const fileName = normalizePath(relative(gitUri.repoPath, gitUri.fsPath)); const title = `Open Changes with Stash${Strings.pad(GlyphChars.Dot, 2, 2)}`; const pick = await StashPicker.show( @@ -83,7 +83,7 @@ export class DiffWithRevisionFromCommand extends ActiveEditorCommand { // Check to see if this file has been renamed const files = await Container.instance.git.getDiffStatus(gitUri.repoPath, 'HEAD', ref, { filters: ['R', 'C'] }); if (files != null) { - const fileName = Strings.normalizePath(relative(gitUri.repoPath, gitUri.fsPath)); + const fileName = normalizePath(relative(gitUri.repoPath, gitUri.fsPath)); const rename = files.find(s => s.fileName === fileName); if (rename?.originalFileName != null) { renamedUri = GitUri.resolveToUri(rename.originalFileName, gitUri.repoPath); diff --git a/src/commands/git/coauthors.ts b/src/commands/git/coauthors.ts index e8a6817..fd6224a 100644 --- a/src/commands/git/coauthors.ts +++ b/src/commands/git/coauthors.ts @@ -2,7 +2,7 @@ import { commands } from 'vscode'; import { Container } from '../../container'; import { GitContributor, Repository } from '../../git/models'; -import { Strings } from '../../system'; +import { normalizePath } from '../../system/path'; import { ViewsWithRepositoryFolders } from '../../views/viewBase'; import { PartialStepState, @@ -104,7 +104,7 @@ export class CoAuthorsGitCommand extends QuickCommand { if (scmRepositories.length) { // Filter out any repo's that are not known to the built-in git context.repos = context.repos.filter(repo => - scmRepositories.find(r => Strings.normalizePath(r.rootUri.fsPath) === repo.path), + scmRepositories.find(r => normalizePath(r.rootUri.fsPath) === repo.path), ); // Ensure that the active repo is known to the built-in git diff --git a/src/commands/openFileAtRevisionFrom.ts b/src/commands/openFileAtRevisionFrom.ts index 1fc26cc..469d3c6 100644 --- a/src/commands/openFileAtRevisionFrom.ts +++ b/src/commands/openFileAtRevisionFrom.ts @@ -1,5 +1,4 @@ 'use strict'; -import { relative } from 'path'; import { TextDocumentShowOptions, TextEditor, Uri } from 'vscode'; import { FileAnnotationType } from '../configuration'; import { GlyphChars, quickPickTitleMaxChars } from '../constants'; @@ -9,6 +8,7 @@ import { GitReference } from '../git/models'; import { Messages } from '../messages'; import { ReferencePicker, StashPicker } from '../quickpicks'; import { Strings } from '../system'; +import { normalizePath, relative } from '../system/path'; import { ActiveEditorCommand, command, Commands, getCommandUri } from './common'; import { GitActions } from './gitCommands'; @@ -44,7 +44,7 @@ export class OpenFileAtRevisionFromCommand extends ActiveEditorCommand { if (args.reference == null) { if (args?.stash) { - const fileName = Strings.normalizePath(relative(gitUri.repoPath, gitUri.fsPath)); + const fileName = normalizePath(relative(gitUri.repoPath, gitUri.fsPath)); const title = `Open Changes with Stash${Strings.pad(GlyphChars.Dot, 2, 2)}`; const pick = await StashPicker.show( diff --git a/src/env/node/git/git.ts b/src/env/node/git/git.ts index 3c29f04..2a8396d 100644 --- a/src/env/node/git/git.ts +++ b/src/env/node/git/git.ts @@ -1,6 +1,5 @@ /* eslint-disable @typescript-eslint/naming-convention */ 'use strict'; -import { dirname, isAbsolute, join as joinPaths } from 'path'; import { Uri, window, workspace } from 'vscode'; import { hrtime } from '@env/hrtime'; import { GlyphChars } from '../../../constants'; @@ -9,7 +8,8 @@ import { GitCommandOptions, GitErrorHandling } from '../../../git/commandOptions import { GitDiffFilter, GitRevision } from '../../../git/models'; import { GitBranchParser, GitLogParser, GitReflogParser, GitStashParser, GitTagParser } from '../../../git/parsers'; import { Logger } from '../../../logger'; -import { Paths, Strings, Versions } from '../../../system'; +import { Strings, Versions } from '../../../system'; +import { dirname, isAbsolute, isFolderGlob, joinPaths, normalizePath, splitPath } from '../../../system/path'; import { GitLocation } from './locator'; import { fsExists, run, RunError, RunOptions } from './shell'; @@ -231,7 +231,7 @@ export namespace Git { ref?: string, options: { args?: string[] | null; ignoreWhitespace?: boolean; startLine?: number; endLine?: number } = {}, ) { - const [file, root] = Paths.splitPath(fileName, repoPath); + const [file, root] = splitPath(fileName, repoPath); const params = ['blame', '--root', '--incremental']; @@ -303,7 +303,7 @@ export namespace Git { endLine?: number; } = {}, ) { - const [file, root] = Paths.splitPath(fileName, repoPath); + const [file, root] = splitPath(fileName, repoPath); const params = ['blame', '--root', '--incremental']; @@ -401,7 +401,7 @@ export namespace Git { params.push(ref, '--'); if (fileName) { - [fileName, repoPath] = Paths.splitPath(fileName, repoPath); + [fileName, repoPath] = splitPath(fileName, repoPath); params.push(fileName); } @@ -804,7 +804,7 @@ export namespace Git { endLine?: number; } = {}, ) { - const [file, root] = Paths.splitPath(fileName, repoPath); + const [file, root] = splitPath(fileName, repoPath); const params = [ 'log', @@ -852,7 +852,7 @@ export namespace Git { if (format !== 'refs') { if (startLine == null) { // If this is the log of a folder, use `--name-status` to match non-file logs (for parsing) - if (format === 'simple' || Paths.isFolderGlob(file)) { + if (format === 'simple' || isFolderGlob(file)) { params.push('--name-status'); } else { params.push('--numstat', '--summary'); @@ -1250,7 +1250,7 @@ export namespace Git { ); // Make sure to normalize: https://github.com/git-for-windows/git/issues/2478 // Keep trailing spaces which are part of the directory name - return data.length === 0 ? undefined : Strings.normalizePath(data.trimLeft().replace(/[\r|\n]+$/, '')); + return data.length === 0 ? undefined : normalizePath(data.trimLeft().replace(/[\r|\n]+$/, '')); } catch (ex) { const inDotGit = /this operation must be run in a work tree/.test(ex.stderr); if (inDotGit || ex.code === 'ENOENT') { @@ -1298,7 +1298,7 @@ export namespace Git { encoding?: 'binary' | 'ascii' | 'utf8' | 'utf16le' | 'ucs2' | 'base64' | 'latin1' | 'hex' | 'buffer'; } = {}, ): Promise { - const [file, root] = Paths.splitPath(fileName, repoPath); + const [file, root] = splitPath(fileName, repoPath); if (GitRevision.isUncommittedStaged(ref)) { ref = ':'; @@ -1482,7 +1482,7 @@ export namespace Git { porcelainVersion: number = 1, { similarityThreshold }: { similarityThreshold?: number | null } = {}, ): Promise { - const [file, root] = Paths.splitPath(fileName, repoPath); + const [file, root] = splitPath(fileName, repoPath); const params = ['status', porcelainVersion >= 2 ? `--porcelain=v${porcelainVersion}` : '--porcelain']; if (await Git.isAtLeastVersion('2.18')) { diff --git a/src/env/node/git/localGitProvider.ts b/src/env/node/git/localGitProvider.ts index eeb0cff..84099ff 100644 --- a/src/env/node/git/localGitProvider.ts +++ b/src/env/node/git/localGitProvider.ts @@ -91,7 +91,8 @@ import { RemoteProvider, RichRemoteProvider } from '../../../git/remotes/provide import { SearchPattern } from '../../../git/search'; import { LogCorrelationContext, Logger } from '../../../logger'; import { Messages } from '../../../messages'; -import { Arrays, debug, Functions, gate, Iterables, log, Paths, Promises, Strings, Versions } from '../../../system'; +import { Arrays, debug, Functions, gate, Iterables, log, Promises, Strings, Versions } from '../../../system'; +import { isFolderGlob, normalizePath, splitPath } from '../../../system/path'; import { PromiseOrValue } from '../../../system/promise'; import { CachedBlame, @@ -225,13 +226,13 @@ export class LocalGitProvider implements GitProvider, Disposable { container.context.subscriptions.push( gitApi.onDidCloseRepository(e => { - const repository = container.git.getCachedRepository(Strings.normalizePath(e.rootUri.fsPath)); + const repository = container.git.getCachedRepository(normalizePath(e.rootUri.fsPath)); if (repository != null) { repository.closed = true; } }), gitApi.onDidOpenRepository(e => { - const repository = container.git.getCachedRepository(Strings.normalizePath(e.rootUri.fsPath)); + const repository = container.git.getCachedRepository(normalizePath(e.rootUri.fsPath)); if (repository != null) { repository.closed = false; } @@ -395,10 +396,10 @@ export class LocalGitProvider implements GitProvider, Disposable { for (let p of repoPaths) { p = dirname(p); // If we are the same as the root, skip it - if (Strings.normalizePath(p) === rootPath) continue; + if (normalizePath(p) === rootPath) continue; Logger.log(cc, `searching in '${p}'...`); - Logger.debug(cc, `normalizedRepoPath=${Strings.normalizePath(p)}, rootPath=${rootPath}`); + Logger.debug(cc, `normalizedRepoPath=${normalizePath(p)}, rootPath=${rootPath}`); const rp = await this.getRepoPath(p, true); if (rp == null) continue; @@ -573,7 +574,7 @@ export class LocalGitProvider implements GitProvider, Disposable { @log({ args: { 1: uris => uris.length } }) async excludeIgnoredUris(repoPath: string, uris: Uri[]): Promise { - const paths = new Map(uris.map(u => [Strings.normalizePath(u.fsPath), u])); + const paths = new Map(uris.map(u => [normalizePath(u.fsPath), u])); const data = await Git.check_ignore(repoPath, ...paths.keys()); if (data == null) return uris; @@ -670,7 +671,7 @@ export class LocalGitProvider implements GitProvider, Disposable { return emptyPromise as Promise; } - const [file, root] = Paths.splitPath(uri.fsPath, uri.repoPath, false); + const [file, root] = splitPath(uri.fsPath, uri.repoPath, false); try { const data = await Git.blame(root, file, uri.sha, { @@ -749,7 +750,7 @@ export class LocalGitProvider implements GitProvider, Disposable { return emptyPromise as Promise; } - const [file, root] = Paths.splitPath(uri.fsPath, uri.repoPath, false); + const [file, root] = splitPath(uri.fsPath, uri.repoPath, false); try { const data = await Git.blame__contents(root, file, contents, { @@ -1420,7 +1421,7 @@ export class LocalGitProvider implements GitProvider, Disposable { key: string, cc: LogCorrelationContext | undefined, ): Promise { - const [file, root] = Paths.splitPath(fileName, repoPath, false); + const [file, root] = splitPath(fileName, repoPath, false); try { const data = await Git.diff(root, file, ref1, ref2, { @@ -1509,7 +1510,7 @@ export class LocalGitProvider implements GitProvider, Disposable { key: string, cc: LogCorrelationContext | undefined, ): Promise { - const [file, root] = Paths.splitPath(fileName, repoPath, false); + const [file, root] = splitPath(fileName, repoPath, false); try { const data = await Git.diff__contents(root, file, ref, contents, { @@ -1931,7 +1932,7 @@ export class LocalGitProvider implements GitProvider, Disposable { skip?: number; }, ): Promise { - if (repoPath != null && repoPath === Strings.normalizePath(fileName)) { + if (repoPath != null && repoPath === normalizePath(fileName)) { throw new Error(`File name cannot match the repository path; fileName=${fileName}`); } @@ -2090,7 +2091,7 @@ export class LocalGitProvider implements GitProvider, Disposable { return emptyPromise as Promise; } - const [file, root] = Paths.splitPath(fileName, repoPath, false); + const [file, root] = splitPath(fileName, repoPath, false); try { if (range != null && range.start.line > range.end.line) { @@ -2107,7 +2108,7 @@ export class LocalGitProvider implements GitProvider, Disposable { const log = GitLogParser.parse( data, // If this is the log of a folder, parse it as a normal log rather than a file log - Paths.isFolderGlob(file) ? GitCommitType.Log : GitCommitType.LogFile, + isFolderGlob(file) ? GitCommitType.Log : GitCommitType.LogFile, root, file, ref, @@ -3056,7 +3057,7 @@ export class LocalGitProvider implements GitProvider, Disposable { ), ); if (networkPath != null) { - repoPath = Strings.normalizePath( + repoPath = normalizePath( repoUri.fsPath.replace( networkPath, `${letter.toLowerCase()}:${networkPath.endsWith('\\') ? '\\' : ''}`, @@ -3067,7 +3068,7 @@ export class LocalGitProvider implements GitProvider, Disposable { } catch {} } - repoPath = Strings.normalizePath(pathUri.fsPath); + repoPath = normalizePath(pathUri.fsPath); } return repoPath; @@ -3089,7 +3090,7 @@ export class LocalGitProvider implements GitProvider, Disposable { return; } - const linkPath = Strings.normalizePath(resolvedPath, { stripTrailingSlash: true }); + const linkPath = normalizePath(resolvedPath); repoPath = repoPath!.replace(linkPath, path); Logger.debug( cc, @@ -3434,16 +3435,14 @@ export class LocalGitProvider implements GitProvider, Disposable { if (typeof filePathOrUri === 'string') { if (ref === GitRevision.deletedOrMissing) return false; - cacheKey = ref ? `${ref}:${Strings.normalizePath(filePathOrUri)}` : Strings.normalizePath(filePathOrUri); - [relativeFilePath, repoPath] = Paths.splitPath(filePathOrUri, repoPath); + cacheKey = ref ? `${ref}:${normalizePath(filePathOrUri)}` : normalizePath(filePathOrUri); + [relativeFilePath, repoPath] = splitPath(filePathOrUri, repoPath); } else { if (!this.isTrackable(filePathOrUri)) return false; // Always use the ref of the GitUri ref = filePathOrUri.sha; - cacheKey = ref - ? `${ref}:${Strings.normalizePath(filePathOrUri.fsPath)}` - : Strings.normalizePath(filePathOrUri.fsPath); + cacheKey = ref ? `${ref}:${normalizePath(filePathOrUri.fsPath)}` : normalizePath(filePathOrUri.fsPath); relativeFilePath = filePathOrUri.fsPath; repoPath = filePathOrUri.repoPath; } @@ -3592,9 +3591,7 @@ export class LocalGitProvider implements GitProvider, Disposable { } const fileName = - typeof fileNameOrUri === 'string' - ? fileNameOrUri - : Strings.normalizePath(relative(repoPath, fileNameOrUri.fsPath)); + typeof fileNameOrUri === 'string' ? fileNameOrUri : normalizePath(relative(repoPath, fileNameOrUri.fsPath)); const blob = await Git.rev_parse__verify(repoPath, ref, fileName); if (blob == null) return GitRevision.deletedOrMissing; @@ -3632,7 +3629,7 @@ export class LocalGitProvider implements GitProvider, Disposable { async stageFile(repoPath: string, fileNameOrUri: string | Uri): Promise { await Git.add( repoPath, - typeof fileNameOrUri === 'string' ? fileNameOrUri : Paths.splitPath(fileNameOrUri.fsPath, repoPath)[0], + typeof fileNameOrUri === 'string' ? fileNameOrUri : splitPath(fileNameOrUri.fsPath, repoPath)[0], ); } @@ -3642,7 +3639,7 @@ export class LocalGitProvider implements GitProvider, Disposable { async stageDirectory(repoPath: string, directoryOrUri: string | Uri): Promise { await Git.add( repoPath, - typeof directoryOrUri === 'string' ? directoryOrUri : Paths.splitPath(directoryOrUri.fsPath, repoPath)[0], + typeof directoryOrUri === 'string' ? directoryOrUri : splitPath(directoryOrUri.fsPath, repoPath)[0], ); } @@ -3652,7 +3649,7 @@ export class LocalGitProvider implements GitProvider, Disposable { async unStageFile(repoPath: string, fileNameOrUri: string | Uri): Promise { await Git.reset( repoPath, - typeof fileNameOrUri === 'string' ? fileNameOrUri : Paths.splitPath(fileNameOrUri.fsPath, repoPath)[0], + typeof fileNameOrUri === 'string' ? fileNameOrUri : splitPath(fileNameOrUri.fsPath, repoPath)[0], ); } @@ -3662,7 +3659,7 @@ export class LocalGitProvider implements GitProvider, Disposable { async unStageDirectory(repoPath: string, directoryOrUri: string | Uri): Promise { await Git.reset( repoPath, - typeof directoryOrUri === 'string' ? directoryOrUri : Paths.splitPath(directoryOrUri.fsPath, repoPath)[0], + typeof directoryOrUri === 'string' ? directoryOrUri : splitPath(directoryOrUri.fsPath, repoPath)[0], ); } @@ -3723,7 +3720,7 @@ export class LocalGitProvider implements GitProvider, Disposable { ' Please retry by stashing everything or install a more recent version of Git and try again.', ); - const pathspecs = uris.map(u => `./${Paths.splitPath(u.fsPath, repoPath)[0]}`); + const pathspecs = uris.map(u => `./${splitPath(u.fsPath, repoPath)[0]}`); const stdinVersion = '2.30.0'; const stdin = await Git.isAtLeastVersion(stdinVersion); diff --git a/src/git/formatters/statusFormatter.ts b/src/git/formatters/statusFormatter.ts index d360713..8c4ef1a 100644 --- a/src/git/formatters/statusFormatter.ts +++ b/src/git/formatters/statusFormatter.ts @@ -1,7 +1,7 @@ 'use strict'; -import { basename } from 'path'; import { GlyphChars } from '../../constants'; import { Strings } from '../../system'; +import { basename } from '../../system/path'; import { GitFile, GitFileWithCommit } from '../models/file'; import { FormatOptions, Formatter } from './formatter'; diff --git a/src/git/fsProvider.ts b/src/git/fsProvider.ts index 7adf540..f4e3173 100644 --- a/src/git/fsProvider.ts +++ b/src/git/fsProvider.ts @@ -1,5 +1,4 @@ 'use strict'; -import { relative } from 'path'; import { Disposable, Event, @@ -15,7 +14,8 @@ import { import { DocumentSchemes } from '../constants'; import { Container } from '../container'; import { GitUri } from '../git/gitUri'; -import { debug, Iterables, Strings, TernarySearchTree } from '../system'; +import { debug, Iterables, TernarySearchTree } from '../system'; +import { normalizePath, relative } from '../system/path'; import { GitRevision, GitTree } from './models'; const emptyArray = new Uint8Array(0); @@ -70,7 +70,7 @@ export class GitFileSystemProvider implements FileSystemProvider, Disposable { const items = [ ...Iterables.map(tree, t => [ - path != null && path.length !== 0 ? Strings.normalizePath(relative(path, t.path)) : t.path, + path != null && path.length !== 0 ? normalizePath(relative(path, t.path)) : t.path, typeToFileType(t.type), ]), ]; diff --git a/src/git/gitProviderService.ts b/src/git/gitProviderService.ts index 8399e86..9dd196e 100644 --- a/src/git/gitProviderService.ts +++ b/src/git/gitProviderService.ts @@ -28,7 +28,8 @@ import { import type { Container } from '../container'; import { ProviderNotFoundError } from '../errors'; import { Logger } from '../logger'; -import { Arrays, debug, gate, Iterables, log, Paths, Promises, Strings } from '../system'; +import { Arrays, debug, gate, Iterables, log, Promises } from '../system'; +import { isDescendent, normalizePath } from '../system/path'; import { PromiseOrValue } from '../system/promise'; import { vslsUriPrefixRegex } from '../vsls/vsls'; import { GitProvider, GitProviderDescriptor, GitProviderId, PagedResult, ScmRepository } from './gitProvider'; @@ -1473,14 +1474,14 @@ export class GitProviderService implements Disposable { let filePath: string; if (typeof repoPathOrUri === 'string') { - filePath = Strings.normalizePath(repoPathOrUri); + filePath = normalizePath(repoPathOrUri); } else { if (GitUri.is(repoPathOrUri) && repoPathOrUri.repoPath) { repo = this.getCachedRepository(repoPathOrUri.repoPath); if (repo != null) return repo; } - filePath = Strings.normalizePath(repoPathOrUri.fsPath); + filePath = normalizePath(repoPathOrUri.fsPath); isVslsScheme = repoPathOrUri.scheme === DocumentSchemes.Vsls; } @@ -1556,7 +1557,7 @@ export class GitProviderService implements Disposable { function findBySubPath(repositories: Map, path: string) { const repos = [...repositories.values()].sort((a, b) => a.path.length - b.path.length); for (const repo of repos) { - if (Paths.isDescendent(path, repo.path)) return repo; + if (isDescendent(path, repo.path)) return repo; } return undefined; @@ -1566,7 +1567,7 @@ export class GitProviderService implements Disposable { // If we can't find the repo and we are a guest, check if we are a "root" workspace if (repo == null && isVslsScheme !== false && this.container.vsls.isMaybeGuest) { if (!vslsUriPrefixRegex.test(path)) { - path = Strings.normalizePath(path); + path = normalizePath(path); const vslsPath = `/~0${path.startsWith(slash) ? path : `/${path}`}`; repo = findBySubPath(this._repositories, vslsPath); } diff --git a/src/git/gitUri.ts b/src/git/gitUri.ts index e0d0ae4..e95b183 100644 --- a/src/git/gitUri.ts +++ b/src/git/gitUri.ts @@ -1,11 +1,12 @@ 'use strict'; -import { basename, dirname, isAbsolute, join as joinPaths, relative } from 'path'; import { Uri } from 'vscode'; import { UriComparer } from '../comparers'; import { DocumentSchemes } from '../constants'; import { Container } from '../container'; import { Logger } from '../logger'; import { debug, memoize, Strings } from '../system'; +import { basename, dirname, isAbsolute, joinPaths, normalizePath, relative } from '../system/path'; +import { CharCode } from '../system/string'; import { GitCommit, GitFile, GitRevision } from './models'; const emptyStr = ''; @@ -165,7 +166,7 @@ export class GitUri extends (Uri as any as UriEx) { @memoize() get relativePath() { - return Strings.normalizePath(this.relativeFsPath); + return normalizePath(this.relativeFsPath); } @memoize() @@ -308,7 +309,7 @@ export class GitUri extends (Uri as any as UriEx) { remoteName: string; } = JSON.parse(uri.query); - let repoPath = Strings.normalizePath(uri.fsPath); + let repoPath = normalizePath(uri.fsPath); if (repoPath.endsWith(data.fileName)) { repoPath = repoPath.substr(0, repoPath.length - data.fileName.length - 1); } else { @@ -329,7 +330,7 @@ export class GitUri extends (Uri as any as UriEx) { static getDirectory(fileName: string, relativeTo?: string): string { let directory: string | undefined = dirname(fileName); - directory = relativeTo != null ? GitUri.relativeTo(directory, relativeTo) : Strings.normalizePath(directory); + directory = relativeTo != null ? GitUri.relativeTo(directory, relativeTo) : normalizePath(directory); return directory == null || directory.length === 0 || directory === '.' ? emptyStr : directory; } @@ -413,7 +414,7 @@ export class GitUri extends (Uri as any as UriEx) { relativeTo == null || relativeTo.length === 0 || !isAbsolute(fileName) ? fileName : relative(relativeTo, fileName); - return Strings.normalizePath(relativePath); + return normalizePath(relativePath); } static git(fileName: string, repoPath?: string) { @@ -431,15 +432,15 @@ export class GitUri extends (Uri as any as UriEx) { } static resolve(fileName: string, repoPath?: string) { - const normalizedFileName = Strings.normalizePath(fileName); + const normalizedFileName = normalizePath(fileName); if (repoPath === undefined) return normalizedFileName; - const normalizedRepoPath = Strings.normalizePath(repoPath); + const normalizedRepoPath = normalizePath(repoPath); if (normalizedFileName == null || normalizedFileName.length === 0) return normalizedRepoPath; if (normalizedFileName.startsWith(normalizedRepoPath)) return normalizedFileName; - return Strings.normalizePath(joinPaths(normalizedRepoPath, normalizedFileName)); + return normalizePath(joinPaths(normalizedRepoPath, normalizedFileName)); } static resolveToUri(fileName: string, repoPath?: string) { @@ -450,7 +451,7 @@ export class GitUri extends (Uri as any as UriEx) { static toKey(uri: Uri): string; static toKey(fileNameOrUri: string | Uri): string; static toKey(fileNameOrUri: string | Uri): string { - return Strings.normalizePath(typeof fileNameOrUri === 'string' ? fileNameOrUri : fileNameOrUri.fsPath); + return normalizePath(typeof fileNameOrUri === 'string' ? fileNameOrUri : fileNameOrUri.fsPath); // return typeof fileNameOrUri === 'string' // ? GitUri.file(fileNameOrUri).toString(true) @@ -493,11 +494,15 @@ export class GitUri extends (Uri as any as UriEx) { return GitRevision.isUncommittedStaged(ref) ? GitUri.git(fileName, repoPath) : Uri.file(fileName); } - const filePath = Strings.normalizePath(fileName, { addLeadingSlash: true }); + let filePath = normalizePath(fileName); + if (filePath.charCodeAt(0) !== CharCode.Slash) { + filePath = `/${filePath}`; + } + const data: UriRevisionData = { path: filePath, ref: ref, - repoPath: Strings.normalizePath(repoPath!), + repoPath: normalizePath(repoPath!), }; const uri = Uri.parse( diff --git a/src/git/models/repository.ts b/src/git/models/repository.ts index 64bee62..d43008e 100644 --- a/src/git/models/repository.ts +++ b/src/git/models/repository.ts @@ -1,5 +1,4 @@ 'use strict'; -import { basename, join as joinPaths, relative } from 'path'; import { commands, ConfigurationChangeEvent, @@ -21,6 +20,7 @@ import { Container } from '../../container'; import { Logger, LogLevel } from '../../logger'; import { Messages } from '../../messages'; import { Arrays, Dates, debug, Functions, gate, Iterables, log, logName } from '../../system'; +import { basename, joinPaths, relative } from '../../system/path'; import { runGitCommandInTerminal } from '../../terminal'; import { GitProviderDescriptor } from '../gitProvider'; import { GitUri } from '../gitUri'; diff --git a/src/git/parsers/blameParser.ts b/src/git/parsers/blameParser.ts index 36572ee..0b96a28 100644 --- a/src/git/parsers/blameParser.ts +++ b/src/git/parsers/blameParser.ts @@ -1,6 +1,6 @@ 'use strict'; -import { relative } from 'path'; import { debug, Strings } from '../../system'; +import { normalizePath, relative } from '../../system/path'; import { GitAuthor, GitBlame, GitBlameCommit, GitCommitLine, GitRevision, GitUser } from '../models'; const emptyStr = ''; @@ -125,13 +125,13 @@ export class GitBlameParser { if (first && repoPath === undefined) { // Try to get the repoPath from the most recent commit - repoPath = Strings.normalizePath( + repoPath = normalizePath( fileName.replace( fileName.startsWith(slash) ? `/${entry.fileName}` : entry.fileName, emptyStr, ), ); - relativeFileName = Strings.normalizePath(relative(repoPath, fileName)); + relativeFileName = normalizePath(relative(repoPath, fileName)); } else { relativeFileName = entry.fileName; } diff --git a/src/git/parsers/logParser.ts b/src/git/parsers/logParser.ts index 9f1c3c1..aa6ea87 100644 --- a/src/git/parsers/logParser.ts +++ b/src/git/parsers/logParser.ts @@ -1,7 +1,7 @@ 'use strict'; -import { relative } from 'path'; import { Range } from 'vscode'; import { Arrays, debug, Strings } from '../../system'; +import { normalizePath, relative } from '../../system/path'; import { GitAuthor, GitCommitType, @@ -112,7 +112,7 @@ export class GitLogParser { if (next.done) return undefined; if (repoPath !== undefined) { - repoPath = Strings.normalizePath(repoPath); + repoPath = normalizePath(repoPath); } const authors = new Map(); @@ -340,13 +340,13 @@ export class GitLogParser { if (first && repoPath === undefined && type === GitCommitType.LogFile && fileName !== undefined) { // Try to get the repoPath from the most recent commit - repoPath = Strings.normalizePath( + repoPath = normalizePath( fileName.replace( fileName.startsWith(slash) ? `/${entry.fileName}` : entry.fileName!, emptyStr, ), ); - relativeFileName = Strings.normalizePath(relative(repoPath, fileName)); + relativeFileName = normalizePath(relative(repoPath, fileName)); } else { relativeFileName = entry.fileName!; } diff --git a/src/git/parsers/stashParser.ts b/src/git/parsers/stashParser.ts index d9aa639..8ec0100 100644 --- a/src/git/parsers/stashParser.ts +++ b/src/git/parsers/stashParser.ts @@ -1,5 +1,6 @@ 'use strict'; import { Arrays, debug, Strings } from '../../system'; +import { normalizePath } from '../../system/path'; import { GitCommitType, GitFile, GitFileIndexStatus, GitStash, GitStashCommit } from '../models'; import { fileStatusRegex } from './logParser'; // import { Logger } from './logger'; @@ -46,7 +47,7 @@ export class GitStashParser { if (next.done) return undefined; if (repoPath !== undefined) { - repoPath = Strings.normalizePath(repoPath); + repoPath = normalizePath(repoPath); } const commits = new Map(); diff --git a/src/git/parsers/statusParser.ts b/src/git/parsers/statusParser.ts index cd37b73..f44cc01 100644 --- a/src/git/parsers/statusParser.ts +++ b/src/git/parsers/statusParser.ts @@ -1,5 +1,6 @@ 'use strict'; -import { debug, Strings } from '../../system'; +import { debug } from '../../system'; +import { normalizePath } from '../../system/path'; import { GitStatus, GitStatusFile } from '../models'; const emptyStr = ''; @@ -58,7 +59,7 @@ export class GitStatusParser { } } - return new GitStatus(Strings.normalizePath(repoPath), branch ?? emptyStr, emptyStr, files, state, upstream); + return new GitStatus(normalizePath(repoPath), branch ?? emptyStr, emptyStr, files, state, upstream); } @debug({ args: false, singleLine: true }) @@ -115,14 +116,7 @@ export class GitStatusParser { } } - return new GitStatus( - Strings.normalizePath(repoPath), - branch ?? emptyStr, - sha ?? emptyStr, - files, - state, - upstream, - ); + return new GitStatus(normalizePath(repoPath), branch ?? emptyStr, sha ?? emptyStr, files, state, upstream); } static parseStatusFile( diff --git a/src/quickpicks/commitQuickPickItems.ts b/src/quickpicks/commitQuickPickItems.ts index c785a20..7b60753 100644 --- a/src/quickpicks/commitQuickPickItems.ts +++ b/src/quickpicks/commitQuickPickItems.ts @@ -1,5 +1,4 @@ 'use strict'; -import { basename } from 'path'; import { QuickPickItem, window } from 'vscode'; import { Commands, GitActions, OpenChangedFilesCommandArgs } from '../commands'; import { GlyphChars } from '../constants'; @@ -8,6 +7,7 @@ import { CommitFormatter } from '../git/formatters'; import { GitFile, GitLogCommit, GitStatusFile } from '../git/models'; import { Keys } from '../keyboard'; import { Strings } from '../system'; +import { basename } from '../system/path'; import { CommandQuickPickItem } from './quickPicksItems'; export class CommitFilesQuickPickItem extends CommandQuickPickItem { diff --git a/src/system.ts b/src/system.ts index b036194..1514944 100644 --- a/src/system.ts +++ b/src/system.ts @@ -29,7 +29,6 @@ export * as Encoding from './system/encoding'; export * as Functions from './system/function'; export * as Iterables from './system/iterable'; export * as Objects from './system/object'; -export * as Paths from './system/path'; export * as Promises from './system/promise'; export * from './system/searchTree'; export * from './system/stopwatch'; diff --git a/src/system/path.ts b/src/system/path.ts index e2602aa..da5053d 100644 --- a/src/system/path.ts +++ b/src/system/path.ts @@ -1,17 +1,20 @@ 'use strict'; import { basename, dirname } from 'path'; import { Uri } from 'vscode'; -import { Strings } from '../system'; -import { normalizePath } from './string'; +import { isWindows } from '@env/platform'; +import { CharCode } from './string'; -const slash = '/'; +export { basename, dirname, extname, isAbsolute, join as joinPaths, relative } from 'path'; + +const driveLetterNormalizeRegex = /(?<=^\/?)([A-Z])(?=:\/)/; +const pathNormalizeRegex = /\\/g; export function isChild(uri: Uri, baseUri: Uri): boolean; export function isChild(uri: Uri, basePath: string): boolean; export function isChild(path: string, basePath: string): boolean; export function isChild(uriOrPath: Uri | string, baseUriOrPath: Uri | string): boolean { if (typeof baseUriOrPath === 'string') { - if (!baseUriOrPath.startsWith('/')) { + if (baseUriOrPath.charCodeAt(0) !== CharCode.Slash) { baseUriOrPath = `/${baseUriOrPath}`; } @@ -37,15 +40,15 @@ export function isDescendent(path: string, basePath: string): boolean; export function isDescendent(uriOrPath: Uri | string, baseUriOrPath: Uri | string): boolean; export function isDescendent(uriOrPath: Uri | string, baseUriOrPath: Uri | string): boolean { if (typeof baseUriOrPath === 'string') { - baseUriOrPath = Strings.normalizePath(baseUriOrPath); - if (!baseUriOrPath.startsWith('/')) { + baseUriOrPath = normalizePath(baseUriOrPath); + if (baseUriOrPath.charCodeAt(0) !== CharCode.Slash) { baseUriOrPath = `/${baseUriOrPath}`; } } if (typeof uriOrPath === 'string') { - uriOrPath = Strings.normalizePath(uriOrPath); - if (!uriOrPath.startsWith('/')) { + uriOrPath = normalizePath(uriOrPath); + if (uriOrPath.charCodeAt(0) !== CharCode.Slash) { uriOrPath = `/${uriOrPath}`; } } @@ -74,16 +77,35 @@ export function isDescendent(uriOrPath: Uri | string, baseUriOrPath: Uri | strin ); } -export function isFolderGlob(path: string) { +export function isFolderGlob(path: string): boolean { return basename(path) === '*'; } +export function normalizePath(fileName: string): string { + if (fileName == null || fileName.length === 0) return fileName; + + let normalized = fileName.replace(pathNormalizeRegex, '/'); + + if (normalized.charCodeAt(normalized.length - 1) === CharCode.Slash) { + normalized = normalized.slice(0, -1); + } + + if (isWindows) { + // Ensure that drive casing is normalized (lower case) + normalized = normalized.replace(driveLetterNormalizeRegex, drive => drive.toLowerCase()); + } + + return normalized; +} + export function splitPath(filePath: string, repoPath: string | undefined, extract: boolean = true): [string, string] { if (repoPath) { filePath = normalizePath(filePath); repoPath = normalizePath(repoPath); - const normalizedRepoPath = (repoPath.endsWith(slash) ? repoPath : `${repoPath}/`).toLowerCase(); + const normalizedRepoPath = ( + repoPath.charCodeAt(repoPath.length - 1) === CharCode.Slash ? repoPath : `${repoPath}/` + ).toLowerCase(); if (filePath.toLowerCase().startsWith(normalizedRepoPath)) { filePath = filePath.substring(normalizedRepoPath.length); } diff --git a/src/system/string.ts b/src/system/string.ts index 98b7e23..7465e2a 100644 --- a/src/system/string.ts +++ b/src/system/string.ts @@ -1,7 +1,6 @@ 'use strict'; import ansiRegex from 'ansi-regex'; import { md5 as _md5 } from '@env/crypto'; -import { isWindows } from '@env/platform'; export { fromBase64, base64 } from '@env/base64'; @@ -159,9 +158,6 @@ export function getSuperscript(num: number) { return superscripts[num - 1] ?? ''; } -const driveLetterNormalizeRegex = /(?<=^\/?)([A-Z])(?=:\/)/; -const pathNormalizeRegex = /\\/g; -const pathStripTrailingSlashRegex = /\/$/g; const tokenRegex = /\$\{('.*?[^\\]'|\W*)?([^|]*?)(?:\|(\d+)(-|\?)?)?('.*?[^\\]'|\W*)?\}/g; const tokenSanitizeRegex = /\$\{(?:'.*?[^\\]'|\W*)?(\w*?)(?:'.*?[^\\]'|[\W\d]*)\}/g; const tokenGroupCharacter = "'"; @@ -285,27 +281,6 @@ export function md5(s: string, encoding: 'base64' | 'hex' = 'base64'): string { return _md5(s, encoding); } -export function normalizePath(fileName: string, options?: { addLeadingSlash?: boolean; stripTrailingSlash?: boolean }) { - if (fileName == null || fileName.length === 0) return fileName; - - let normalized = fileName.replace(pathNormalizeRegex, '/'); - - if (options?.stripTrailingSlash ?? true) { - normalized = normalized.replace(pathStripTrailingSlashRegex, emptyStr); - } - - if ((options?.addLeadingSlash ?? false) && normalized.charCodeAt(0) !== CharCode.Slash) { - normalized = `/${normalized}`; - } - - if (isWindows) { - // Ensure that drive casing is normalized (lower case) - normalized = normalized.replace(driveLetterNormalizeRegex, drive => drive.toLowerCase()); - } - - return normalized; -} - export function pad(s: string, before: number = 0, after: number = 0, padding: string = '\u00a0') { if (before === 0 && after === 0) return s; diff --git a/src/views/nodes/branchTrackingStatusFilesNode.ts b/src/views/nodes/branchTrackingStatusFilesNode.ts index 812571d..67ebf94 100644 --- a/src/views/nodes/branchTrackingStatusFilesNode.ts +++ b/src/views/nodes/branchTrackingStatusFilesNode.ts @@ -1,10 +1,10 @@ 'use strict'; -import { join as joinPaths } from 'path'; import { TreeItem, TreeItemCollapsibleState } from 'vscode'; import { ViewFilesLayout } from '../../configuration'; import { GitUri } from '../../git/gitUri'; import { GitBranch, GitFileWithCommit, GitRevision } from '../../git/models'; import { Arrays, Iterables, Strings } from '../../system'; +import { joinPaths, normalizePath } from '../../system/path'; import { ViewsWithCommits } from '../viewBase'; import { BranchNode } from './branchNode'; import { BranchTrackingStatus } from './branchTrackingStatusNode'; @@ -84,7 +84,7 @@ export class BranchTrackingStatusFilesNode extends ViewNode { const hierarchy = Arrays.makeHierarchical( children, n => n.uri.relativePath.split('/'), - (...parts: string[]) => Strings.normalizePath(joinPaths(...parts)), + (...parts: string[]) => normalizePath(joinPaths(...parts)), this.view.config.files.compact, ); diff --git a/src/views/nodes/commitFileNode.ts b/src/views/nodes/commitFileNode.ts index b911442..26dd102 100644 --- a/src/views/nodes/commitFileNode.ts +++ b/src/views/nodes/commitFileNode.ts @@ -1,10 +1,10 @@ 'use strict'; -import { dirname, join as joinPaths } from 'path'; import { Command, Selection, TreeItem, TreeItemCollapsibleState, Uri } from 'vscode'; import { Commands, DiffWithPreviousCommandArgs } from '../../commands'; import { StatusFileFormatter } from '../../git/formatters'; import { GitUri } from '../../git/gitUri'; import { GitBranch, GitFile, GitLogCommit, GitRevisionReference } from '../../git/models'; +import { dirname, joinPaths } from '../../system/path'; import { FileHistoryView } from '../fileHistoryView'; import { View, ViewsWithCommits } from '../viewBase'; import { ContextValues, ViewNode, ViewRefFileNode } from './viewNode'; diff --git a/src/views/nodes/commitNode.ts b/src/views/nodes/commitNode.ts index 8388caf..385b769 100644 --- a/src/views/nodes/commitNode.ts +++ b/src/views/nodes/commitNode.ts @@ -1,5 +1,4 @@ 'use strict'; -import { join as joinPaths } from 'path'; import { Command, MarkdownString, ThemeColor, ThemeIcon, TreeItem, TreeItemCollapsibleState } from 'vscode'; import { Commands, DiffWithPreviousCommandArgs } from '../../commands'; import { ViewFilesLayout } from '../../configuration'; @@ -7,6 +6,7 @@ import { Colors, GlyphChars } from '../../constants'; import { CommitFormatter } from '../../git/formatters'; import { GitBranch, GitLogCommit, GitRevisionReference } from '../../git/models'; import { Arrays, Strings } from '../../system'; +import { joinPaths, normalizePath } from '../../system/path'; import { FileHistoryView } from '../fileHistoryView'; import { TagsView } from '../tagsView'; import { ViewsWithCommits } from '../viewBase'; @@ -57,7 +57,7 @@ export class CommitNode extends ViewRefNode n.uri.relativePath.split('/'), - (...parts: string[]) => Strings.normalizePath(joinPaths(...parts)), + (...parts: string[]) => normalizePath(joinPaths(...parts)), this.view.config.files.compact, ); diff --git a/src/views/nodes/fileHistoryNode.ts b/src/views/nodes/fileHistoryNode.ts index 6d5c67e..8d3cf90 100644 --- a/src/views/nodes/fileHistoryNode.ts +++ b/src/views/nodes/fileHistoryNode.ts @@ -1,5 +1,4 @@ 'use strict'; -import { basename, join as joinPaths } from 'path'; import { Disposable, TreeItem, TreeItemCollapsibleState, window } from 'vscode'; import { configuration } from '../../configuration'; import { GitUri } from '../../git/gitUri'; @@ -14,6 +13,7 @@ import { } from '../../git/models'; import { Logger } from '../../logger'; import { Arrays, debug, gate, Iterables, memoize } from '../../system'; +import { basename, joinPaths } from '../../system/path'; import { FileHistoryView } from '../fileHistoryView'; import { CommitNode } from './commitNode'; import { LoadMoreNode, MessageNode } from './common'; diff --git a/src/views/nodes/fileRevisionAsCommitNode.ts b/src/views/nodes/fileRevisionAsCommitNode.ts index b4d5264..aff4c8d 100644 --- a/src/views/nodes/fileRevisionAsCommitNode.ts +++ b/src/views/nodes/fileRevisionAsCommitNode.ts @@ -1,5 +1,4 @@ 'use strict'; -import { join as joinPaths } from 'path'; import { Command, MarkdownString, @@ -15,6 +14,7 @@ import { Colors, GlyphChars } from '../../constants'; import { CommitFormatter, StatusFileFormatter } from '../../git/formatters'; import { GitUri } from '../../git/gitUri'; import { GitBranch, GitFile, GitLogCommit, GitRevisionReference } from '../../git/models'; +import { joinPaths } from '../../system/path'; import { FileHistoryView } from '../fileHistoryView'; import { LineHistoryView } from '../lineHistoryView'; import { ViewsWithCommits } from '../viewBase'; diff --git a/src/views/nodes/mergeConflictFileNode.ts b/src/views/nodes/mergeConflictFileNode.ts index 7e659e6..3274902 100644 --- a/src/views/nodes/mergeConflictFileNode.ts +++ b/src/views/nodes/mergeConflictFileNode.ts @@ -1,10 +1,10 @@ 'use strict'; -import { dirname } from 'path'; import { Command, ThemeIcon, TreeItem, TreeItemCollapsibleState, Uri } from 'vscode'; import { BuiltInCommands } from '../../constants'; import { StatusFileFormatter } from '../../git/formatters'; import { GitUri } from '../../git/gitUri'; import { GitFile, GitMergeStatus, GitRebaseStatus } from '../../git/models'; +import { dirname } from '../../system/path'; import { ViewsWithCommits } from '../viewBase'; import { FileNode } from './folderNode'; import { MergeConflictCurrentChangesNode } from './mergeConflictCurrentChangesNode'; diff --git a/src/views/nodes/mergeStatusNode.ts b/src/views/nodes/mergeStatusNode.ts index 003bc8c..b375cdd 100644 --- a/src/views/nodes/mergeStatusNode.ts +++ b/src/views/nodes/mergeStatusNode.ts @@ -1,10 +1,10 @@ 'use strict'; -import { join as joinPaths } from 'path'; import { MarkdownString, ThemeColor, ThemeIcon, TreeItem, TreeItemCollapsibleState } from 'vscode'; import { ViewFilesLayout } from '../../configuration'; import { GitUri } from '../../git/gitUri'; import { GitBranch, GitMergeStatus, GitReference, GitStatus } from '../../git/models'; import { Arrays, Strings } from '../../system'; +import { joinPaths, normalizePath } from '../../system/path'; import { ViewsWithCommits } from '../viewBase'; import { BranchNode } from './branchNode'; import { FileNode, FolderNode } from './folderNode'; @@ -48,7 +48,7 @@ export class MergeStatusNode extends ViewNode { const hierarchy = Arrays.makeHierarchical( children, n => n.uri.relativePath.split('/'), - (...parts: string[]) => Strings.normalizePath(joinPaths(...parts)), + (...parts: string[]) => normalizePath(joinPaths(...parts)), this.view.config.files.compact, ); diff --git a/src/views/nodes/rebaseStatusNode.ts b/src/views/nodes/rebaseStatusNode.ts index bb132dd..a155706 100644 --- a/src/views/nodes/rebaseStatusNode.ts +++ b/src/views/nodes/rebaseStatusNode.ts @@ -1,5 +1,4 @@ 'use strict'; -import { join as joinPaths } from 'path'; import { Command, commands, @@ -24,6 +23,7 @@ import { GitStatus, } from '../../git/models'; import { Arrays, Strings } from '../../system'; +import { joinPaths, normalizePath } from '../../system/path'; import { ViewsWithCommits } from '../viewBase'; import { BranchNode } from './branchNode'; import { CommitFileNode } from './commitFileNode'; @@ -65,7 +65,7 @@ export class RebaseStatusNode extends ViewNode { const hierarchy = Arrays.makeHierarchical( children, n => n.uri.relativePath.split('/'), - (...parts: string[]) => Strings.normalizePath(joinPaths(...parts)), + (...parts: string[]) => normalizePath(joinPaths(...parts)), this.view.config.files.compact, ); @@ -182,7 +182,7 @@ export class RebaseCommitNode extends ViewRefNode n.uri.relativePath.split('/'), - (...parts: string[]) => Strings.normalizePath(joinPaths(...parts)), + (...parts: string[]) => normalizePath(joinPaths(...parts)), this.view.config.files.compact, ); diff --git a/src/views/nodes/resultsFileNode.ts b/src/views/nodes/resultsFileNode.ts index c618793..ca5e3d6 100644 --- a/src/views/nodes/resultsFileNode.ts +++ b/src/views/nodes/resultsFileNode.ts @@ -1,10 +1,10 @@ 'use strict'; -import { dirname, join as joinPaths } from 'path'; import { Command, TreeItem, TreeItemCollapsibleState } from 'vscode'; import { Commands, DiffWithCommandArgs } from '../../commands'; import { StatusFileFormatter } from '../../git/formatters'; import { GitUri } from '../../git/gitUri'; import { GitFile, GitReference, GitRevisionReference } from '../../git/models'; +import { dirname, joinPaths } from '../../system/path'; import { View } from '../viewBase'; import { FileNode } from './folderNode'; import { ContextValues, ViewNode, ViewRefFileNode } from './viewNode'; diff --git a/src/views/nodes/resultsFilesNode.ts b/src/views/nodes/resultsFilesNode.ts index 9f82f6d..b3c2a93 100644 --- a/src/views/nodes/resultsFilesNode.ts +++ b/src/views/nodes/resultsFilesNode.ts @@ -1,10 +1,10 @@ 'use strict'; -import { join as joinPaths } from 'path'; import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from 'vscode'; import { ViewFilesLayout } from '../../configuration'; import { GitUri } from '../../git/gitUri'; import { GitFile } from '../../git/models'; import { Arrays, debug, gate, Iterables, Promises, Strings } from '../../system'; +import { joinPaths, normalizePath } from '../../system/path'; import { ViewsWithCommits } from '../viewBase'; import { FileNode, FolderNode } from './folderNode'; import { ResultsFileNode } from './resultsFileNode'; @@ -78,7 +78,7 @@ export class ResultsFilesNode extends ViewNode { const hierarchy = Arrays.makeHierarchical( children, n => n.uri.relativePath.split('/'), - (...parts: string[]) => Strings.normalizePath(joinPaths(...parts)), + (...parts: string[]) => normalizePath(joinPaths(...parts)), this.view.config.files.compact, ); diff --git a/src/views/nodes/stashNode.ts b/src/views/nodes/stashNode.ts index d071ffc..4ec33e9 100644 --- a/src/views/nodes/stashNode.ts +++ b/src/views/nodes/stashNode.ts @@ -1,10 +1,10 @@ 'use strict'; -import { join as joinPaths } from 'path'; import { TreeItem, TreeItemCollapsibleState } from 'vscode'; import { ViewFilesLayout } from '../../config'; import { CommitFormatter } from '../../git/formatters'; import { GitStashCommit, GitStashReference } from '../../git/models'; import { Arrays, Strings } from '../../system'; +import { joinPaths, normalizePath } from '../../system/path'; import { ContextValues, FileNode, FolderNode, RepositoryNode, StashFileNode, ViewNode, ViewRefNode } from '../nodes'; import { RepositoriesView } from '../repositoriesView'; import { StashesView } from '../stashesView'; @@ -43,7 +43,7 @@ export class StashNode extends ViewRefNode n.uri.relativePath.split('/'), - (...parts: string[]) => Strings.normalizePath(joinPaths(...parts)), + (...parts: string[]) => normalizePath(joinPaths(...parts)), this.view.config.files.compact, ); diff --git a/src/views/nodes/statusFileNode.ts b/src/views/nodes/statusFileNode.ts index b3e2fb4..3addda8 100644 --- a/src/views/nodes/statusFileNode.ts +++ b/src/views/nodes/statusFileNode.ts @@ -1,11 +1,11 @@ 'use strict'; -import { dirname, join as joinPaths } from 'path'; import { Command, ThemeIcon, TreeItem, TreeItemCollapsibleState } from 'vscode'; import { Commands, DiffWithCommandArgs, DiffWithPreviousCommandArgs } from '../../commands'; import { StatusFileFormatter } from '../../git/formatters/statusFormatter'; import { GitUri } from '../../git/gitUri'; import { GitFile, GitLogCommit } from '../../git/models'; import { Strings } from '../../system'; +import { dirname, joinPaths } from '../../system/path'; import { ViewsWithCommits } from '../viewBase'; import { FileRevisionAsCommitNode } from './fileRevisionAsCommitNode'; import { FileNode } from './folderNode'; diff --git a/src/views/nodes/statusFilesNode.ts b/src/views/nodes/statusFilesNode.ts index 6d39d66..0841764 100644 --- a/src/views/nodes/statusFilesNode.ts +++ b/src/views/nodes/statusFilesNode.ts @@ -1,5 +1,4 @@ 'use strict'; -import { join as joinPaths } from 'path'; import { TreeItem, TreeItemCollapsibleState } from 'vscode'; import { ViewFilesLayout } from '../../configuration'; import { GitUri } from '../../git/gitUri'; @@ -14,6 +13,7 @@ import { GitTrackingState, } from '../../git/models'; import { Arrays, Iterables, Strings } from '../../system'; +import { joinPaths, normalizePath } from '../../system/path'; import { RepositoriesView } from '../repositoriesView'; import { FileNode, FolderNode } from './folderNode'; import { RepositoryNode } from './repositoryNode'; @@ -111,7 +111,7 @@ export class StatusFilesNode extends ViewNode { const hierarchy = Arrays.makeHierarchical( children, n => n.uri.relativePath.split('/'), - (...parts: string[]) => Strings.normalizePath(joinPaths(...parts)), + (...parts: string[]) => normalizePath(joinPaths(...parts)), this.view.config.files.compact, ); diff --git a/src/vsls/host.ts b/src/vsls/host.ts index 2c36067..e2a89e2 100644 --- a/src/vsls/host.ts +++ b/src/vsls/host.ts @@ -5,7 +5,8 @@ import type { LiveShare, SharedService } from '../@types/vsls'; import { Container } from '../container'; import { GitUri } from '../git/gitUri'; import { Logger } from '../logger'; -import { debug, Iterables, log, Strings } from '../system'; +import { debug, Iterables, log } from '../system'; +import { normalizePath } from '../system/path'; import { GitCommandRequest, GitCommandRequestType, @@ -111,8 +112,8 @@ export class VslsHostService implements Disposable { let localPath; let sharedPath; for (const f of workspace.workspaceFolders) { - localPath = Strings.normalizePath(f.uri.fsPath); - sharedPath = Strings.normalizePath(this.convertLocalUriToShared(f.uri).fsPath); + localPath = normalizePath(f.uri.fsPath); + sharedPath = normalizePath(this.convertLocalUriToShared(f.uri).fsPath); Logger.debug(cc, `shared='${sharedPath}' \u2194 local='${localPath}'`); this._localToSharedPaths.set(localPath, sharedPath); @@ -142,7 +143,7 @@ export class VslsHostService implements Disposable { if (options.cwd !== undefined && options.cwd.length > 0 && this._sharedToLocalPaths !== undefined) { // This is all so ugly, but basically we are converting shared paths to local paths if (this._sharedPathsRegex?.test(options.cwd)) { - options.cwd = Strings.normalizePath(options.cwd).replace(this._sharedPathsRegex, (match, shared) => { + options.cwd = normalizePath(options.cwd).replace(this._sharedPathsRegex, (match, shared) => { if (!isRootWorkspace) { isRootWorkspace = shared === '/~0'; } @@ -180,7 +181,7 @@ export class VslsHostService implements Disposable { args.splice( i, 1, - Strings.normalizePath(arg).replace(this._sharedPathsRegex, (match, shared) => { + normalizePath(arg).replace(this._sharedPathsRegex, (match, shared) => { const local = this._sharedToLocalPaths.get(shared); return local != null ? local : shared; }), @@ -212,7 +213,7 @@ export class VslsHostService implements Disposable { _cancellation: CancellationToken, ): Promise { const uri = this.convertSharedUriToLocal(Uri.parse(request.folderUri)); - const normalized = Strings.normalizePath(uri.fsPath, { stripTrailingSlash: true }).toLowerCase(); + const normalized = normalizePath(uri.fsPath).toLowerCase(); const repos = [ ...Iterables.filterMap(this.container.git.repositories, r => { diff --git a/src/webviews/rebaseEditor.ts b/src/webviews/rebaseEditor.ts index 00e7f84..ed8a26a 100644 --- a/src/webviews/rebaseEditor.ts +++ b/src/webviews/rebaseEditor.ts @@ -22,7 +22,8 @@ import { Container } from '../container'; import { RepositoryChange, RepositoryChangeComparisonMode } from '../git/models'; import { Logger } from '../logger'; import { Messages } from '../messages'; -import { debug, gate, Iterables, Strings } from '../system'; +import { debug, gate, Iterables } from '../system'; +import { normalizePath } from '../system/path'; import { Author, Commit, @@ -164,7 +165,7 @@ export class RebaseEditorProvider implements CustomTextEditorProvider, Disposabl @debug({ args: false }) async resolveCustomTextEditor(document: TextDocument, panel: WebviewPanel, _token: CancellationToken) { - const repoPath = Strings.normalizePath(Uri.joinPath(document.uri, '..', '..', '..').fsPath); + const repoPath = normalizePath(Uri.joinPath(document.uri, '..', '..', '..').fsPath); const repo = await this.container.git.getRepository(repoPath); const subscriptions: Disposable[] = [];