diff --git a/CHANGELOG.md b/CHANGELOG.md index 8483096..e52eb92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,8 +23,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p - Fixes an issue where gravatar icons would sometimes not show up — thanks to [PR #579](https://github.com/eamodio/vscode-gitlens/pull/579) by sgtwilko ([@sgtwilko](https://github.com/sgtwilko)) - Fixes [#501](https://github.com/eamodio/vscode-gitlens/issues/501) — Azure DevOps ssh remotes aren't handled properly +- Fixes [#566](https://github.com/eamodio/vscode-gitlens/issues/566) — History error with UNC - Fixes [#572](https://github.com/eamodio/vscode-gitlens/issues/572) — Explorer cant expand some branch folders - Fixes an issue where comparing a file with its staged revision doesn't show any content +- Fixes an issue where the workspace folder added by the _Explore Repository from Here_ command (`gitlens.views.exploreRepoRevision`) would fail to load in certain cases ## [9.0.3] - 2018-12-06 diff --git a/src/commands/common.ts b/src/commands/common.ts index 143d51a..6e5e210 100644 --- a/src/commands/common.ts +++ b/src/commands/common.ts @@ -505,7 +505,7 @@ export async function openEditor( const { rethrow, ...opts } = options; try { if (uri instanceof GitUri) { - uri = uri.documentUri({ noSha: true }); + uri = uri.documentUri(); } if (uri.scheme === DocumentSchemes.GitLens && ImageMimetypes[paths.extname(uri.fsPath)]) { diff --git a/src/git/fsProvider.ts b/src/git/fsProvider.ts index b44ffa4..c8edbfb 100644 --- a/src/git/fsProvider.ts +++ b/src/git/fsProvider.ts @@ -113,6 +113,18 @@ export class GitFileSystemProvider implements FileSystemProvider, Disposable { treeItem = (await searchTree).get(`/~/${path}`); } else { + if (path == null || path.length === 0) { + const tree = await this.getTree(path, ref, repoPath); + if (tree === undefined) throw FileSystemError.FileNotFound(uri); + + return { + type: FileType.Directory, + size: 0, + ctime: 0, + mtime: 0 + }; + } + treeItem = await Container.git.getTreeFileForRevision(repoPath, path, ref); } diff --git a/src/git/gitService.ts b/src/git/gitService.ts index d7280da..b22e90d 100644 --- a/src/git/gitService.ts +++ b/src/git/gitService.ts @@ -1871,7 +1871,7 @@ export class GitService implements Disposable { @log() async getTreeFileForRevision(repoPath: string, fileName: string, ref: string): Promise { - if (repoPath === undefined) return undefined; + if (repoPath === undefined || fileName == null || fileName.length === 0) return undefined; const data = await Git.ls_tree(repoPath, ref, { fileName: fileName }); const trees = GitTreeParser.parse(data); diff --git a/src/git/gitUri.ts b/src/git/gitUri.ts index 6d02211..09589fd 100644 --- a/src/git/gitUri.ts +++ b/src/git/gitUri.ts @@ -7,6 +7,9 @@ import { Container } from '../container'; import { GitCommit, GitFile, GitService } from '../git/gitService'; import { Strings } from '../system'; +const empty = ''; +const slash = '/'; + export interface GitCommitish { fileName?: string; repoPath: string; @@ -30,8 +33,6 @@ interface UriEx { new (components: UriComponents): Uri; } -const stripRepoRevisionFromPathRegex = /^\/<.+>\/?(.*)$/; - export class GitUri extends ((Uri as any) as UriEx) { repoPath?: string; sha?: string; @@ -50,13 +51,10 @@ export class GitUri extends ((Uri as any) as UriEx) { if (uri.scheme === DocumentSchemes.GitLens) { const data = JSON.parse(uri.query) as IUriRevisionData; - data.repoPath = Strings.normalizePath(data.repoPath); - data.path = Strings.normalizePath( - `/${data.repoPath}/${uri.path.replace(stripRepoRevisionFromPathRegex, '$1')}` - ); - // Make sure we aren't starting with // - if (data.path[1] === '/') { - data.path = data.path.substr(1); + // When Uri's come from the FileSystemProvider, the uri.query only contains the root repo info (not the actual file path), so fix that here + const index = uri.path.indexOf(data.path); + if (index + data.path.length < uri.path.length) { + data.path = uri.path.substr(index); } super({ @@ -100,9 +98,9 @@ export class GitUri extends ((Uri as any) as UriEx) { case 'http': case 'file': if (!fsPath) { - path = '/'; + path = slash; } - else if (fsPath[0] !== '/') { + else if (fsPath[0] !== slash) { path = `/${fsPath}`; } else { @@ -132,10 +130,11 @@ export class GitUri extends ((Uri as any) as UriEx) { return this.sha && GitService.shortenSha(this.sha); } - documentUri(options: { noSha?: boolean; useVersionedPath?: boolean } = {}) { + documentUri(options: { useVersionedPath?: boolean } = {}) { if (options.useVersionedPath && this.versionedPath !== undefined) return GitUri.file(this.versionedPath); + if (this.scheme !== 'file') return this; - return this.scheme === 'file' ? GitUri.file(!options.noSha && this.sha ? this.path : this.fsPath) : this; + return GitUri.file(this.fsPath); } equals(uri: Uri | undefined) { @@ -156,10 +155,10 @@ export class GitUri extends ((Uri as any) as UriEx) { } getFormattedPath(options: { relativeTo?: string; separator?: string; suffix?: string } = {}): string { - const { relativeTo = this.repoPath, separator = Strings.pad(GlyphChars.Dot, 2, 2), suffix = '' } = options; + const { relativeTo = this.repoPath, separator = Strings.pad(GlyphChars.Dot, 2, 2), suffix = empty } = options; const directory = GitUri.getDirectory(this.fsPath, relativeTo); - return `${paths.basename(this.fsPath)}${suffix}${directory ? `${separator}${directory}` : ''}`; + return `${paths.basename(this.fsPath)}${suffix}${directory ? `${separator}${directory}` : empty}`; } getRelativePath(relativeTo?: string): string { @@ -175,20 +174,17 @@ export class GitUri extends ((Uri as any) as UriEx) { } private static ensureValidUNCPath(authority: string, fsPath: string): [string, string] { - // Taken from https://github.com/Microsoft/vscode/blob/master/src/vs/base/common/uri.ts#L239-L251 + // Taken from https://github.com/Microsoft/vscode/blob/e444eaa768a1e8bd8315f2cee265d725e96a8162/src/vs/base/common/uri.ts#L300-L325 // check for authority as used in UNC shares or use the path as given - if ( - fsPath.charCodeAt(0) === Strings.CharCode.Backslash && - fsPath.charCodeAt(1) === Strings.CharCode.Backslash - ) { - const index = fsPath.indexOf('\\', 2); + if (fsPath[0] === slash && fsPath[1] === slash) { + const index = fsPath.indexOf(slash, 2); if (index === -1) { authority = fsPath.substring(2); - fsPath = '\\'; + fsPath = slash; } else { authority = fsPath.substring(2, index); - fsPath = fsPath.substring(index) || '\\'; + fsPath = fsPath.substring(index) || slash; } } @@ -250,7 +246,7 @@ export class GitUri extends ((Uri as any) as UriEx) { let ref; switch (data.ref) { - case '': + case empty: case '~': ref = GitService.stagedUncommittedSha; break; @@ -280,14 +276,14 @@ export class GitUri extends ((Uri as any) as UriEx) { directory = paths.relative(relativeTo, directory); } directory = Strings.normalizePath(directory); - return !directory || directory === '.' ? '' : directory; + return !directory || directory === '.' ? empty : directory; } static getFormattedPath( fileNameOrUri: string | Uri, options: { relativeTo?: string; separator?: string; suffix?: string } = {} ): string { - const { relativeTo, separator = Strings.pad(GlyphChars.Dot, 2, 2), suffix = '' } = options; + const { relativeTo, separator = Strings.pad(GlyphChars.Dot, 2, 2), suffix = empty } = options; let fileName: string; if (fileNameOrUri instanceof Uri) { @@ -342,6 +338,7 @@ export class GitUri extends ((Uri as any) as UriEx) { if (normalizedFileName == null || normalizedFileName.length === 0) return normalizedRepoPath; if (normalizedFileName.startsWith(normalizedRepoPath)) return normalizedFileName; + return Strings.normalizePath(paths.join(normalizedRepoPath, normalizedFileName)); } @@ -388,19 +385,18 @@ export class GitUri extends ((Uri as any) as UriEx) { repoPath = Strings.normalizePath(repoPath!); const repoName = paths.basename(repoPath); + + const filePath = Strings.normalizePath(fileName, { addLeadingSlash: true }); const data: IUriRevisionData = { - path: Strings.normalizePath(fileName, { addLeadingSlash: true }), + path: filePath, ref: ref, repoPath: repoPath }; - let filePath = Strings.normalizePath(paths.relative(repoPath, fileName), { addLeadingSlash: true }); - if (filePath === '/') { - filePath = ''; - } - const uri = Uri.parse( - `${DocumentSchemes.GitLens}://git/<${repoName}@${shortSha}>${filePath}?${JSON.stringify(data)}` + `${DocumentSchemes.GitLens}:///${repoName}@${shortSha}${ + filePath === slash ? empty : filePath + }?${JSON.stringify(data)}` ); return uri; }