'use strict'; import { Uri } from 'vscode'; import { DocumentSchemes } from '../constants'; import { GitService, IGitStatusFile } from '../gitService'; import * as path from 'path'; export class GitUri extends Uri { offset: number; repoPath?: string | undefined; sha?: string | undefined; constructor(uri?: Uri, commit?: IGitCommitInfo); constructor(uri?: Uri, repoPath?: string); constructor(uri?: Uri, commitOrRepoPath?: IGitCommitInfo | string); constructor(uri?: Uri, commitOrRepoPath?: IGitCommitInfo | string) { super(); if (!uri) return; const base = this as any; base._scheme = uri.scheme; base._authority = uri.authority; base._path = uri.path; base._query = uri.query; base._fragment = uri.fragment; this.offset = 0; if (uri.scheme === DocumentSchemes.GitLensGit) { const data = GitService.fromGitContentUri(uri); base._fsPath = path.resolve(data.repoPath, data.originalFileName || data.fileName); this.offset = (data.decoration && data.decoration.split('\n').length) || 0; if (!GitService.isUncommitted(data.sha)) { this.sha = data.sha; this.repoPath = data.repoPath; } } else if (commitOrRepoPath) { if (typeof commitOrRepoPath === 'string') { this.repoPath = commitOrRepoPath; } else { const commit = commitOrRepoPath; base._fsPath = path.resolve(commit.repoPath, commit.originalFileName || commit.fileName); if (commit.repoPath !== undefined) { this.repoPath = commit.repoPath; } if (commit.sha !== undefined && !GitService.isUncommitted(commit.sha)) { this.sha = commit.sha; } } } } get shortSha() { return this.sha && this.sha.substring(0, 8); } fileUri() { return Uri.file(this.sha ? this.path : this.fsPath); } getFormattedPath(separator: string = ' \u00a0\u2022\u00a0 '): string { let directory = path.dirname(this.fsPath); if (this.repoPath) { directory = path.relative(this.repoPath, directory); } directory = GitService.normalizePath(directory); return (!directory || directory === '.') ? path.basename(this.fsPath) : `${path.basename(this.fsPath)}${separator}${directory}`; } getRelativePath(): string { return GitService.normalizePath(path.relative(this.repoPath || '', this.fsPath)); } static async fromUri(uri: Uri, git: GitService) { if (uri instanceof GitUri) return uri; if (!git.isTrackable(uri)) return new GitUri(uri, git.repoPath); const gitUri = git.getGitUriForFile(uri.fsPath); if (gitUri) return gitUri; // If this is a git uri, assume it is showing the most recent commit if (uri.scheme === DocumentSchemes.Git && uri.query === '~') { const commit = await git.getLogCommit(undefined, uri.fsPath); if (commit) return new GitUri(uri, commit); } return new GitUri(uri, (await git.getRepoPathFromFile(uri.fsPath)) || git.repoPath); } static fromFileStatus(status: IGitStatusFile, repoPath: string, original?: boolean): GitUri; static fromFileStatus(status: IGitStatusFile, commit: IGitCommitInfo, original?: boolean): GitUri; static fromFileStatus(status: IGitStatusFile, repoPathOrCommit: string | IGitCommitInfo, original: boolean = false): GitUri { const repoPath = typeof repoPathOrCommit === 'string' ? repoPathOrCommit : repoPathOrCommit.repoPath; const uri = Uri.file(path.resolve(repoPath, original ? status.originalFileName || status.fileName : status.fileName)); return new GitUri(uri, repoPathOrCommit); } } export interface IGitCommitInfo { fileName: string; repoPath: string; sha?: string; originalFileName?: string; } export interface IGitUriData { sha: string; fileName: string; repoPath: string; originalFileName?: string; index?: number; decoration?: string; }