diff --git a/src/GitHub.App/SampleData/PullRequestDetailViewModelDesigner.cs b/src/GitHub.App/SampleData/PullRequestDetailViewModelDesigner.cs index a7f84838f..97bbd454a 100644 --- a/src/GitHub.App/SampleData/PullRequestDetailViewModelDesigner.cs +++ b/src/GitHub.App/SampleData/PullRequestDetailViewModelDesigner.cs @@ -70,6 +70,7 @@ This requires that errors be propagated from the viewmodel to the view and from public IPullRequestModel Model { get; } public string SourceBranchDisplayName { get; set; } public string TargetBranchDisplayName { get; set; } + public bool IsCheckedOut { get; } public bool IsFromFork { get; } public string Body { get; } public IReactiveList ChangedFilesTree { get; } @@ -84,12 +85,12 @@ This requires that errors be propagated from the viewmodel to the view and from public ReactiveCommand OpenFile { get; } public ReactiveCommand DiffFile { get; } - public Task ExtractFile(IPullRequestFileNode file) + public Task> ExtractDiffFiles(IPullRequestFileNode file) { return null; } - public Task> ExtractDiffFiles(IPullRequestFileNode file) + public string GetLocalFilePath(IPullRequestFileNode file) { return null; } diff --git a/src/GitHub.App/Services/PullRequestService.cs b/src/GitHub.App/Services/PullRequestService.cs index c054ddbc1..be7adb4fa 100644 --- a/src/GitHub.App/Services/PullRequestService.cs +++ b/src/GitHub.App/Services/PullRequestService.cs @@ -287,7 +287,8 @@ namespace GitHub.Services IModelService modelService, IPullRequestModel pullRequest, string fileName, - string fileSha) + string fileSha, + bool isPullRequestBranchCheckedOut) { return Observable.Defer(async () => { @@ -300,7 +301,9 @@ namespace GitHub.Services // The right file - if it comes from a fork - may not be fetched so fall back to // getting the file contents from the model service. - var right = await GetFileFromRepositoryOrApi(repository, repo, modelService, pullRequest.Head.Sha, fileName, fileSha); + var right = isPullRequestBranchCheckedOut ? + Path.Combine(repository.LocalPath, fileName) : + await GetFileFromRepositoryOrApi(repository, repo, modelService, pullRequest.Head.Sha, fileName, fileSha); if (left == null) { diff --git a/src/GitHub.App/ViewModels/PullRequestDetailViewModel.cs b/src/GitHub.App/ViewModels/PullRequestDetailViewModel.cs index e04cb3baf..7900b0070 100644 --- a/src/GitHub.App/ViewModels/PullRequestDetailViewModel.cs +++ b/src/GitHub.App/ViewModels/PullRequestDetailViewModel.cs @@ -39,6 +39,7 @@ namespace GitHub.ViewModels IPullRequestCheckoutState checkoutState; IPullRequestUpdateState updateState; string operationError; + bool isCheckedOut; bool isFromFork; bool isInCheckout; @@ -103,7 +104,7 @@ namespace GitHub.ViewModels SubscribeOperationError(Push); OpenOnGitHub = ReactiveCommand.Create(); - OpenFile = ReactiveCommand.Create(); + OpenFile = ReactiveCommand.Create(this.WhenAnyValue(x => x.IsCheckedOut)); DiffFile = ReactiveCommand.Create(); } @@ -145,6 +146,15 @@ namespace GitHub.ViewModels private set { this.RaiseAndSetIfChanged(ref targetBranchDisplayName, value); } } + /// + /// Gets a value indicating whether the pull request branch is checked out. + /// + public bool IsCheckedOut + { + get { return isCheckedOut; } + private set { this.RaiseAndSetIfChanged(ref isCheckedOut, value); } + } + /// /// Gets a value indicating whether the pull request comes from a fork. /// @@ -269,9 +279,10 @@ namespace GitHub.ViewModels } var localBranches = await pullRequestsService.GetLocalBranches(repository, pullRequest).ToList(); - var isCheckedOut = localBranches.Contains(repository.CurrentBranch); - if (isCheckedOut) + IsCheckedOut = localBranches.Contains(repository.CurrentBranch); + + if (IsCheckedOut) { var divergence = await pullRequestsService.CalculateHistoryDivergence(repository, Model.Number); var pullEnabled = divergence.BehindBy > 0; @@ -339,17 +350,6 @@ namespace GitHub.ViewModels } } - /// - /// Gets the specified file as it appears in the pull request. - /// - /// The file or directory node. - /// The path to the extracted file. - public Task ExtractFile(IPullRequestFileNode file) - { - var path = Path.Combine(file.DirectoryPath, file.FileName); - return pullRequestsService.ExtractFile(repository, modelService, model.Head.Sha, path, file.Sha).ToTask(); - } - /// /// Gets the before and after files needed for viewing a diff. /// @@ -358,7 +358,17 @@ namespace GitHub.ViewModels public Task> ExtractDiffFiles(IPullRequestFileNode file) { var path = Path.Combine(file.DirectoryPath, file.FileName); - return pullRequestsService.ExtractDiffFiles(repository, modelService, model, path, file.Sha).ToTask(); + return pullRequestsService.ExtractDiffFiles(repository, modelService, model, path, file.Sha, IsCheckedOut).ToTask(); + } + + /// + /// Gets the full path to a file in the working directory. + /// + /// The file. + /// The full path to the file in the working directory. + public string GetLocalFilePath(IPullRequestFileNode file) + { + return Path.Combine(repository.LocalPath, file.DirectoryPath, file.FileName); } void SubscribeOperationError(ReactiveCommand command) diff --git a/src/GitHub.Exports.Reactive/Services/IPullRequestService.cs b/src/GitHub.Exports.Reactive/Services/IPullRequestService.cs index 0c7a8bd91..2cece4d4e 100644 --- a/src/GitHub.Exports.Reactive/Services/IPullRequestService.cs +++ b/src/GitHub.Exports.Reactive/Services/IPullRequestService.cs @@ -120,13 +120,18 @@ namespace GitHub.Services /// The pull request details. /// The filename relative to the repository root. /// The SHA of the file in the pull request. - /// The filenames of the left and right files for the diff. + /// + /// Whether the pull request branch is currently checked out. If so the right file returned + /// will be the path to the file in the working directory. + /// + /// The paths of the left and right files for the diff. IObservable> ExtractDiffFiles( ILocalRepositoryModel repository, IModelService modelService, IPullRequestModel pullRequest, string fileName, - string fileSha); + string fileSha, + bool isPullRequestBranchCheckedOut); /// /// Remotes all unused remotes that were created by GitHub for Visual Studio to track PRs diff --git a/src/GitHub.Exports.Reactive/ViewModels/IPullRequestDetailViewModel.cs b/src/GitHub.Exports.Reactive/ViewModels/IPullRequestDetailViewModel.cs index 9e1fada96..233fd9aa3 100644 --- a/src/GitHub.Exports.Reactive/ViewModels/IPullRequestDetailViewModel.cs +++ b/src/GitHub.Exports.Reactive/ViewModels/IPullRequestDetailViewModel.cs @@ -79,6 +79,11 @@ namespace GitHub.ViewModels /// string TargetBranchDisplayName { get; } + /// + /// Gets a value indicating whether the pull request branch is checked out. + /// + bool IsCheckedOut { get; } + /// /// Gets a value indicating whether the pull request comes from a fork. /// @@ -139,18 +144,18 @@ namespace GitHub.ViewModels /// ReactiveCommand DiffFile { get; } - /// - /// Gets the specified file as it appears in the pull request. - /// - /// The file or directory node. - /// The path to the extracted file. - Task ExtractFile(IPullRequestFileNode file); - /// /// Gets the before and after files needed for viewing a diff. /// /// The changed file. /// A tuple containing the full path to the before and after files. Task> ExtractDiffFiles(IPullRequestFileNode file); + + /// + /// Gets the full path to a file in the working directory. + /// + /// The file. + /// The full path to the file in the working directory. + string GetLocalFilePath(IPullRequestFileNode file); } } diff --git a/src/GitHub.VisualStudio/UI/Views/PullRequestDetailView.xaml b/src/GitHub.VisualStudio/UI/Views/PullRequestDetailView.xaml index d1d0e49b7..5f508e2f1 100644 --- a/src/GitHub.VisualStudio/UI/Views/PullRequestDetailView.xaml +++ b/src/GitHub.VisualStudio/UI/Views/PullRequestDetailView.xaml @@ -286,8 +286,8 @@ - + diff --git a/src/GitHub.VisualStudio/UI/Views/PullRequestDetailView.xaml.cs b/src/GitHub.VisualStudio/UI/Views/PullRequestDetailView.xaml.cs index 9bce7a980..ff1c41c22 100644 --- a/src/GitHub.VisualStudio/UI/Views/PullRequestDetailView.xaml.cs +++ b/src/GitHub.VisualStudio/UI/Views/PullRequestDetailView.xaml.cs @@ -41,7 +41,7 @@ namespace GitHub.VisualStudio.UI.Views this.WhenActivated(d => { d(ViewModel.OpenOnGitHub.Subscribe(_ => DoOpenOnGitHub())); - d(ViewModel.OpenFile.Subscribe(x => DoOpenFile((IPullRequestFileNode)x).Forget())); + d(ViewModel.OpenFile.Subscribe(x => DoOpenFile((IPullRequestFileNode)x))); d(ViewModel.DiffFile.Subscribe(x => DoDiffFile((IPullRequestFileNode)x).Forget())); }); } @@ -65,15 +65,12 @@ namespace GitHub.VisualStudio.UI.Views browser.OpenUrl(url); } - async Task DoOpenFile(IPullRequestFileNode file) + void DoOpenFile(IPullRequestFileNode file) { try { - var fileName = await ViewModel.ExtractFile(file); - var window = Services.Dte.ItemOperations.OpenFile(fileName); - - // If the file we extracted isn't the current file on disk, make the window read-only. - window.Document.ReadOnly = fileName != file.DirectoryPath; + var fileName = ViewModel.GetLocalFilePath(file); + Services.Dte.ItemOperations.OpenFile(fileName); } catch (Exception e) { @@ -86,21 +83,28 @@ namespace GitHub.VisualStudio.UI.Views try { var fileNames = await ViewModel.ExtractDiffFiles(file); - var leftLabel = $"{file.FileName};{ViewModel.TargetBranchDisplayName}"; - var rightLabel = $"{file.FileName};PR {ViewModel.Model.Number}"; + var leftLabel = $"{file.FileName};{ViewModel.TargetBranchDisplayName}"; + var rightLabel = $"{file.FileName};PR {ViewModel.Model.Number}"; + var caption = $"Diff - {file.FileName}"; + var tooltip = $"{leftLabel}\nvs.\n{rightLabel}"; + var options = __VSDIFFSERVICEOPTIONS.VSDIFFOPT_DetectBinaryFiles | + __VSDIFFSERVICEOPTIONS.VSDIFFOPT_LeftFileIsTemporary; - Services.DifferenceService.OpenComparisonWindow2( - fileNames.Item1, - fileNames.Item2, - $"{leftLabel} vs {rightLabel}", - file.DirectoryPath, - leftLabel, - rightLabel, - string.Empty, - string.Empty, - (int)(__VSDIFFSERVICEOPTIONS.VSDIFFOPT_DetectBinaryFiles | - __VSDIFFSERVICEOPTIONS.VSDIFFOPT_LeftFileIsTemporary | - __VSDIFFSERVICEOPTIONS.VSDIFFOPT_RightFileIsTemporary)); + if (!ViewModel.IsCheckedOut) + { + options |= __VSDIFFSERVICEOPTIONS.VSDIFFOPT_RightFileIsTemporary; + } + + Services.DifferenceService.OpenComparisonWindow2( + fileNames.Item1, + fileNames.Item2, + caption, + tooltip, + leftLabel, + rightLabel, + string.Empty, + string.Empty, + (uint)options); } catch (Exception e) { diff --git a/submodules/GitHubVSAutomationIDs b/submodules/GitHubVSAutomationIDs index e3a4c2ed7..3105a88ca 160000 --- a/submodules/GitHubVSAutomationIDs +++ b/submodules/GitHubVSAutomationIDs @@ -1 +1 @@ -Subproject commit e3a4c2ed78980e4a2379716062e9e4ae04c44e8a +Subproject commit 3105a88caaef9b7059f3779843b8b2c8feb5390a