/// <inheritdoc/> public Uri ToRepositoryUrl(GitHubContext context) { var builder = new UriBuilder("https", context.Host ?? "github.com"); builder.Path = $"{context.Owner}/{context.RepositoryName}"; return(builder.Uri); }
static void SetSelection(IVsTextView textView, GitHubContext context) { var line = context.Line; var lineEnd = context.LineEnd ?? line; if (line != null) { ErrorHandler.ThrowOnFailure(textView.GetBuffer(out IVsTextLines buffer)); buffer.GetLengthOfLine(lineEnd.Value - 1, out int lineEndLength); ErrorHandler.ThrowOnFailure(textView.SetSelection(line.Value - 1, 0, lineEnd.Value - 1, lineEndLength)); ErrorHandler.ThrowOnFailure(textView.CenterLines(line.Value - 1, lineEnd.Value - line.Value + 1)); } }
/// <inheritdoc/> public bool TryOpenFile(string repositoryDir, GitHubContext context) { var(commitish, path, isSha) = ResolveBlob(repositoryDir, context); if (path == null) { return(false); } var fullPath = Path.Combine(repositoryDir, path.Replace('/', '\\')); var textView = OpenDocument(fullPath); SetSelection(textView, context); return(true); }
/// <inheritdoc/> public GitHubContext FindContextFromUrl(string url) { var uri = new UriString(url); if (!uri.IsValidUri) { return(null); } if (!uri.IsHypertextTransferProtocol) { return(null); } var context = new GitHubContext { Host = uri.Host, Owner = uri.Owner, RepositoryName = uri.RepositoryName, Url = uri }; var repositoryPrefix = uri.ToRepositoryUrl().ToString() + "/"; if (!url.StartsWith(repositoryPrefix, StringComparison.OrdinalIgnoreCase)) { return(context); } var subpath = url.Substring(repositoryPrefix.Length); (context.Line, context.LineEnd) = FindLine(subpath); context.PullRequest = FindPullRequest(url); var match = urlBlobRegex.Match(subpath); if (match.Success) { context.TreeishPath = match.Groups["treeish"].Value; context.BlobName = match.Groups["blobName"].Value; context.LinkType = LinkType.Blob; return(context); } return(context); }
/// <inheritdoc/> public void TryNavigateToContext(string repositoryDir, GitHubContext context) { if (context?.LinkType == LinkType.Blob) { var(commitish, path, commitSha) = ResolveBlob(repositoryDir, context); if (commitish == null && path == null) { var message = string.Format(CultureInfo.CurrentCulture, Resources.CouldntFindCorrespondingFile, context.Url); vsServices.ShowMessageBoxInfo(message); return; } var hasChanges = HasChangesInWorkingDirectory(repositoryDir, commitish, path); if (hasChanges) { var message = string.Format(CultureInfo.CurrentCulture, Resources.ChangesInWorkingDirectoryMessage, commitish); vsServices.ShowMessageBoxInfo(message); } TryOpenFile(repositoryDir, context); } }
/// <inheritdoc/> public async Task <bool> TryAnnotateFile(string repositoryDir, string currentBranch, GitHubContext context) { var(commitish, path, commitSha) = ResolveBlob(repositoryDir, context); if (path == null) { return(false); } if (!AnnotateFile(repositoryDir, currentBranch, path, commitSha)) { return(false); } if (context.Line != null) { await Task.Delay(1000); var activeView = FindActiveView(); SetSelection(activeView, context); } return(true); }
/// <inheritdoc/> public (string commitish, string path, string commitSha) ResolveBlob(string repositoryDir, GitHubContext context, string remoteName = "origin") { Guard.ArgumentNotNull(repositoryDir, nameof(repositoryDir)); Guard.ArgumentNotNull(context, nameof(context)); using (var repository = gitService.GetRepository(repositoryDir)) { if (context.TreeishPath == null) { // Blobs without a TreeishPath aren't currently supported return(null, null, null); } if (context.BlobName == null) { // Not a blob return(null, null, null); } var objectishPath = $"{context.TreeishPath}/{context.BlobName}"; var objectish = ToObjectish(objectishPath); var(commitSha, pathSha) = objectish.First(); if (ObjectId.TryParse(commitSha, out ObjectId objectId) && repository.Lookup(objectId) != null) { if (repository.Lookup($"{commitSha}:{pathSha}") != null) { return(commitSha, pathSha, commitSha); } } foreach (var(commitish, path) in objectish) { var resolveRefs = new[] { $"refs/remotes/{remoteName}/{commitish}", $"refs/tags/{commitish}" }; foreach (var resolveRef in resolveRefs) { var commit = repository.Lookup(resolveRef); if (commit != null) { var blob = repository.Lookup($"{resolveRef}:{path}"); if (blob != null) { return(resolveRef, path, commit.Sha); } // Resolved commitish but not path return(resolveRef, null, commit.Sha); } } } return(null, null, null); } IEnumerable <(string commitish, string path)> ToObjectish(string treeishPath) { var index = 0; while ((index = treeishPath.IndexOf('/', index + 1)) != -1) { var commitish = treeishPath.Substring(0, index); var path = treeishPath.Substring(index + 1); yield return(commitish, path); } } }