async Task SessionChanged(IPullRequestSession session)
        {
            this.session = session;
            fileSubscription?.Dispose();

            if (session == null)
            {
                Thread = null;
                threadSubscription?.Dispose();
                return;
            }

            var relativePath = session.GetRelativePath(fullPath);

            file = await session.GetFile(relativePath);

            fileSubscription = file.WhenAnyValue(x => x.InlineCommentThreads).Subscribe(_ => UpdateThread().Forget());
        }
示例#2
0
        /// <summary>
        /// Initializes a new instance of the <see cref="PullRequestReviewViewModel"/> class.
        /// </summary>
        /// <param name="editorService">The pull request editor service.</param>
        /// <param name="session">The pull request session.</param>
        /// <param name="model">The pull request review model.</param>
        public PullRequestReviewViewModel(
            IPullRequestEditorService editorService,
            IPullRequestSession session,
            PullRequestReviewModel model)
        {
            Guard.ArgumentNotNull(editorService, nameof(editorService));
            Guard.ArgumentNotNull(session, nameof(session));
            Guard.ArgumentNotNull(model, nameof(model));

            Model        = model;
            Body         = string.IsNullOrWhiteSpace(Model.Body) ? null : Model.Body;
            StateDisplay = ToString(Model.State);

            var comments = new List <IPullRequestReviewFileCommentViewModel>();
            var outdated = new List <IPullRequestReviewFileCommentViewModel>();

            foreach (var comment in model.Comments)
            {
                if (comment.Thread != null)
                {
                    var vm = new PullRequestReviewCommentViewModel(
                        editorService,
                        session,
                        comment.Thread.Path,
                        comment);

                    if (comment.Thread.Position != null)
                    {
                        comments.Add(vm);
                    }
                    else
                    {
                        outdated.Add(vm);
                    }
                }
            }

            FileComments         = comments;
            OutdatedFileComments = outdated;

            HasDetails = Body != null ||
                         FileComments.Count > 0 ||
                         OutdatedFileComments.Count > 0;
        }
        async Task StatusChanged()
        {
            try
            {
                var session = CurrentSession;

                var pr = await service.GetPullRequestForCurrentBranch(repository).FirstOrDefaultAsync();

                if (pr != null)
                {
                    var changePR =
                        pr.Item1 != (session?.PullRequest.Base.RepositoryCloneUrl.Owner) ||
                        pr.Item2 != (session?.PullRequest.Number);

                    if (changePR)
                    {
                        var modelService = await connectionManager.GetModelService(repository, modelServiceFactory);

                        var pullRequest = await modelService?.GetPullRequest(pr.Item1, repository.Name, pr.Item2);

                        if (pullRequest != null)
                        {
                            var newSession = await GetSessionInternal(pullRequest);

                            if (newSession != null)
                            {
                                newSession.IsCheckedOut = true;
                            }
                            session = newSession;
                        }
                    }
                }
                else
                {
                    session = null;
                }

                CurrentSession = session;
            }
            catch (Exception e)
            {
                log.Error(e, "Error changing repository");
            }
        }
示例#4
0
        public async Task Initialize(
            IPullRequestSession session,
            IApiClient apiClient)
        {
            Guard.ArgumentNotNull(session, nameof(session));
            Guard.ArgumentNotNull(apiClient, nameof(apiClient));

            if (this.session != null)
            {
                return;
            }

            this.session = session;

            var viewModel = new PullRequestCommentsViewModel(apiClient, session);
            await viewModel.Initialize();

            view.DataContext = viewModel;
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="PullRequestReviewCommentViewModel"/> class.
 /// </summary>
 /// <param name="session">The pull request session.</param>
 /// <param name="thread">The thread that the comment is a part of.</param>
 /// <param name="currentUser">The current user.</param>
 /// <param name="model">The comment model.</param>
 public PullRequestReviewCommentViewModel(
     IPullRequestSession session,
     ICommentThreadViewModel thread,
     IActorViewModel currentUser,
     PullRequestReviewModel review,
     PullRequestReviewCommentModel model)
     : this(
         session,
         thread,
         currentUser,
         model.Id,
         model.Body,
         CommentEditState.None,
         new ActorViewModel(model.Author),
         model.CreatedAt,
         review.State == PullRequestReviewState.Pending,
         model.Url != null ? new Uri(model.Url) : null)
 {
 }
示例#6
0
 /// <summary>
 /// Creates a placeholder comment which can be used to add a new comment to a thread.
 /// </summary>
 /// <param name="session">The pull request session.</param>
 /// <param name="thread">The comment thread.</param>
 /// <param name="currentUser">The current user.</param>
 /// <returns>THe placeholder comment.</returns>
 public static CommentViewModel CreatePlaceholder(
     IPullRequestSession session,
     ICommentThreadViewModel thread,
     IActorViewModel currentUser)
 {
     return(new PullRequestReviewCommentViewModel(
                session,
                thread,
                currentUser,
                0,
                null,
                0,
                string.Empty,
                CommentEditState.Placeholder,
                currentUser,
                DateTimeOffset.MinValue,
                false,
                null));
 }
示例#7
0
        async Task RefreshCurrentSession(LocalRepositoryModel repository, IPullRequestSession session)
        {
            if (repository != null && repository.HasRemotesButNoOrigin)
            {
                NoRemoteOriginCallout();
            }

            var showStatus = await IsDotComOrEnterpriseRepository(repository);

            if (!showStatus)
            {
                ShowStatus(null);
                return;
            }

            var viewModel = CreatePullRequestStatusViewModel(repository, session);

            ShowStatus(viewModel);
        }
示例#8
0
        /// <inheritdoc/>
        public async Task InitializeAsync(
            IPullRequestSession session,
            Func <IInlineCommentThreadModel, bool> filter = null)
        {
            Guard.ArgumentNotNull(session, nameof(session));

            subscriptions?.Dispose();
            this.pullRequestSession = session;
            this.commentFilter      = filter;
            subscriptions           = new CompositeDisposable();
            subscriptions.Add(session.WhenAnyValue(x => x.IsCheckedOut).Subscribe(isBranchCheckedOut));

            var dirs = new Dictionary <string, PullRequestDirectoryNode>
            {
                { string.Empty, new PullRequestDirectoryNode(string.Empty) }
            };

            using (var changes = await service.GetTreeChanges(session.LocalRepository, session.PullRequest))
            {
                foreach (var changedFile in session.PullRequest.ChangedFiles)
                {
                    var node = new PullRequestFileNode(
                        session.LocalRepository.LocalPath,
                        changedFile.FileName,
                        changedFile.Sha,
                        changedFile.Status,
                        GetOldFileName(changedFile, changes));
                    var file = await session.GetFile(changedFile.FileName);

                    if (file != null)
                    {
                        subscriptions.Add(file.WhenAnyValue(x => x.InlineCommentThreads)
                                          .Subscribe(x => node.CommentCount = CountComments(x, filter)));
                    }

                    var dir = GetDirectory(Path.GetDirectoryName(node.RelativePath), dirs);
                    dir.Files.Add(node);
                }
            }

            ChangedFilesCount = session.PullRequest.ChangedFiles.Count;
            Items             = dirs[string.Empty].Children.ToList();
        }
示例#9
0
        public PullRequestCommentsViewModel(
            IPullRequestSession session)
        {
            this.session = session;

            Repository = session.LocalRepository;
            Number     = session.PullRequest.Number;
            Title      = session.PullRequest.Title;

            Conversation = new IssueCommentThreadViewModel(Repository, Number, session.User);

            foreach (var comment in session.PullRequest.Comments)
            {
                Conversation.Comments.Add(new CommentViewModel(
                                              Conversation,
                                              session.User,
                                              comment));
            }
        }
        async Task RefreshCurrentSession(ILocalRepositoryModel repository, IPullRequestSession session)
        {
            try
            {
                var showStatus = await IsDotComOrEnterpriseRepository(repository);

                if (!showStatus)
                {
                    ShowStatus(null);
                    return;
                }

                var viewModel = CreatePullRequestStatusViewModel(session);
                ShowStatus(viewModel);
            }
            catch (Exception e)
            {
                log.Error(e, nameof(RefreshCurrentSession));
            }
        }
示例#11
0
        /// <summary>
        /// Initializes a new instance of the <see cref="InlineCommentThreadViewModel"/> class.
        /// </summary>
        /// <param name="apiClient">The API client to use to post/update comments.</param>
        /// <param name="session">The current PR review session.</param>
        public InlineCommentThreadViewModel(
            IPullRequestSession session,
            IEnumerable <IPullRequestReviewCommentModel> comments)
            : base(session.User)
        {
            Guard.ArgumentNotNull(session, nameof(session));

            Session = session;

            PostComment = ReactiveCommand.CreateAsyncTask(
                Observable.Return(true),
                DoPostComment);

            foreach (var comment in comments)
            {
                Comments.Add(new CommentViewModel(this, CurrentUser, comment));
            }

            Comments.Add(CommentViewModel.CreatePlaceholder(this, CurrentUser));
        }
示例#12
0
        void AddBufferTag(
            ITextBuffer buffer,
            IPullRequestSession session,
            string path,
            string commitSha,
            DiffSide?side)
        {
            buffer.Properties.GetOrCreateSingletonProperty(
                typeof(PullRequestTextBufferInfo),
                () => new PullRequestTextBufferInfo(session, path, commitSha, side));

            var projection = buffer as IProjectionBuffer;

            if (projection != null)
            {
                foreach (var source in projection.SourceBuffers)
                {
                    AddBufferTag(source, session, path, commitSha, side);
                }
            }
        }
示例#13
0
        /// <summary>
        /// Initializes a new instance of the <see cref="PullRequestReviewCommentViewModel"/> class.
        /// </summary>
        /// <param name="session">The pull request session.</param>
        /// <param name="commentService">The comment service</param>
        /// <param name="thread">The thread that the comment is a part of.</param>
        /// <param name="currentUser">The current user.</param>
        /// <param name="pullRequestId">The pull request id of the comment.</param>
        /// <param name="commentId">The GraphQL ID of the comment.</param>
        /// <param name="databaseId">The database id of the comment.</param>
        /// <param name="body">The comment body.</param>
        /// <param name="state">The comment edit state.</param>
        /// <param name="author">The author of the comment.</param>
        /// <param name="updatedAt">The modified date of the comment.</param>
        /// <param name="isPending">Whether this is a pending comment.</param>
        /// <param name="webUrl"></param>
        public PullRequestReviewCommentViewModel(
            IPullRequestSession session,
            ICommentService commentService,
            ICommentThreadViewModel thread,
            IActorViewModel currentUser,
            int pullRequestId,
            string commentId,
            int databaseId,
            string body,
            CommentEditState state,
            IActorViewModel author,
            DateTimeOffset updatedAt,
            bool isPending,
            Uri webUrl)
            : base(commentService, thread, currentUser, pullRequestId, commentId, databaseId, body, state, author, updatedAt, webUrl)
        {
            Guard.ArgumentNotNull(session, nameof(session));

            this.session = session;
            IsPending    = isPending;

            var pendingReviewAndIdObservable = Observable.CombineLatest(
                session.WhenAnyValue(x => x.HasPendingReview, x => !x),
                this.WhenAnyValue(model => model.Id).Select(i => i == null),
                (hasPendingReview, isNewComment) => new { hasPendingReview, isNewComment });

            canStartReview = pendingReviewAndIdObservable
                             .Select(arg => arg.hasPendingReview && arg.isNewComment)
                             .ToProperty(this, x => x.CanStartReview);

            commitCaption = pendingReviewAndIdObservable
                            .Select(arg => !arg.isNewComment ? Resources.UpdateComment : arg.hasPendingReview ? Resources.AddSingleComment : Resources.AddReviewComment)
                            .ToProperty(this, x => x.CommitCaption);

            StartReview = ReactiveCommand.CreateAsyncTask(
                CommitEdit.CanExecuteObservable,
                DoStartReview);
            AddErrorHandler(StartReview);
        }
示例#14
0
        async Task <PullRequestReviewCommentThreadViewModel> CreateTarget(
            IViewViewModelFactory factory             = null,
            IPullRequestSession session               = null,
            IPullRequestSessionFile file              = null,
            PullRequestReviewModel review             = null,
            IEnumerable <InlineCommentModel> comments = null)
        {
            factory  = factory ?? CreateFactory();
            session  = session ?? CreateSession();
            file     = file ?? Substitute.For <IPullRequestSessionFile>();
            review   = review ?? new PullRequestReviewModel();
            comments = comments ?? CreateComments();

            var thread = Substitute.For <IInlineCommentThreadModel>();

            thread.Comments.Returns(comments.ToList());

            var result = new PullRequestReviewCommentThreadViewModel(factory);
            await result.InitializeAsync(session, file, review, thread, true);

            return(result);
        }
        static async Task <PullRequestReviewCommentViewModel> CreateTarget(
            IPullRequestSession session           = null,
            ICommentService commentService        = null,
            ICommentThreadViewModel thread        = null,
            ActorModel currentUser                = null,
            PullRequestReviewModel review         = null,
            PullRequestReviewCommentModel comment = null)
        {
            session        = session ?? CreateSession();
            commentService = commentService ?? Substitute.For <ICommentService>();
            thread         = thread ?? CreateThread();
            currentUser    = currentUser ?? new ActorModel {
                Login = "******"
            };
            comment = comment ?? new PullRequestReviewCommentModel();
            review  = review ?? CreateReview(PullRequestReviewState.Approved, comment);

            var result = new PullRequestReviewCommentViewModel(commentService);
            await result.InitializeAsync(session, thread, review, comment, CommentEditState.None);

            return(result);
        }
        static PullRequestReviewCommentViewModel CreateTarget(
            IPullRequestSession session           = null,
            ICommentThreadViewModel thread        = null,
            ActorModel currentUser                = null,
            PullRequestReviewModel review         = null,
            PullRequestReviewCommentModel comment = null)
        {
            session     = session ?? CreateSession();
            thread      = thread ?? CreateThread();
            currentUser = currentUser ?? new ActorModel {
                Login = "******"
            };
            comment = comment ?? new PullRequestReviewCommentModel();
            review  = review ?? CreateReview(comment);

            return(new PullRequestReviewCommentViewModel(
                       session,
                       thread,
                       new ActorViewModel(currentUser),
                       review,
                       comment));
        }
示例#17
0
        void Initialize()
        {
            document = buffer.Properties.GetProperty <ITextDocument>(typeof(ITextDocument));

            if (document == null)
            {
                return;
            }

            var bufferInfo = sessionManager.GetTextBufferInfo(buffer);
            IPullRequestSession session = null;

            if (bufferInfo != null)
            {
                fullPath     = bufferInfo.FilePath;
                leftHandSide = bufferInfo.IsLeftComparisonBuffer;

                if (!bufferInfo.Session.IsCheckedOut)
                {
                    session = bufferInfo.Session;
                }
            }
            else
            {
                fullPath = document.FilePath;
            }

            if (session == null)
            {
                managerSubscription = sessionManager.WhenAnyValue(x => x.CurrentSession).Subscribe(SessionChanged);
            }
            else
            {
                SessionChanged(session);
            }

            initialized = true;
        }
        void Initialize()
        {
            document = TryGetDocument(buffer);

            if (document == null)
            {
                return;
            }

            var bufferInfo = sessionManager.GetTextBufferInfo(buffer);
            IPullRequestSession session = null;

            if (bufferInfo != null)
            {
                fullPath     = bufferInfo.FilePath;
                leftHandSide = bufferInfo.IsLeftComparisonBuffer;

                if (!bufferInfo.Session.IsCheckedOut)
                {
                    session = bufferInfo.Session;
                }
            }
            else
            {
                fullPath = document.FilePath;
            }

            if (session == null)
            {
                managerSubscription = sessionManager.WhenAnyValue(x => x.CurrentSession).Subscribe(x => ForgetWithLogging(SessionChanged(x)));
            }
            else
            {
                ForgetWithLogging(SessionChanged(session));
            }

            initialized = true;
        }
示例#19
0
        IDifferenceViewer FocusExistingDiffViewer(
            IPullRequestSession session,
            string mergeBase,
            string rightPath)
        {
            IVsUIHierarchy uiHierarchy;
            uint           itemID;
            IVsWindowFrame windowFrame;

            // Diff documents are indexed by the path on the right hand side of the comparison.
            if (VsShellUtilities.IsDocumentOpen(
                    serviceProvider,
                    rightPath,
                    Guid.Empty,
                    out uiHierarchy,
                    out itemID,
                    out windowFrame))
            {
                var diffViewer = GetDiffViewer(windowFrame);

                if (diffViewer != null)
                {
                    PullRequestTextBufferInfo leftBufferInfo;

                    if (diffViewer.LeftView.TextBuffer.Properties.TryGetProperty(
                            typeof(PullRequestTextBufferInfo),
                            out leftBufferInfo) &&
                        leftBufferInfo.Session.PullRequest.Number == session.PullRequest.Number &&
                        leftBufferInfo.CommitSha == mergeBase)
                    {
                        ErrorHandler.ThrowOnFailure(windowFrame.Show());
                        return(diffViewer);
                    }
                }
            }

            return(null);
        }
示例#20
0
        /// <inheritdoc/>
        public async Task <IDifferenceViewer> OpenDiff(
            IPullRequestSession session,
            string relativePath,
            IInlineCommentThreadModel thread)
        {
            Guard.ArgumentNotNull(session, nameof(session));
            Guard.ArgumentNotEmptyString(relativePath, nameof(relativePath));
            Guard.ArgumentNotNull(thread, nameof(thread));

            var diffViewer = await OpenDiff(session, relativePath, thread.CommitSha, scrollToFirstDiff : false);

            var param = (object)new InlineCommentNavigationParams
            {
                FromLine = thread.LineNumber - 1,
            };

            // HACK: We need to wait here for the inline comment tags to initialize so we can find the next inline comment.
            // There must be a better way of doing this.
            await Task.Delay(1500);

            RaiseWhenAvailable(Guids.CommandSetString, PkgCmdIDList.NextInlineCommentId, param);

            return(diffViewer);
        }
 static void RaisePullRequestChanged(IPullRequestSession session, PullRequestDetailModel newPullRequest)
 {
     ((ISubject <PullRequestDetailModel>)session.PullRequestChanged).OnNext(newPullRequest);
 }
示例#22
0
        /// <inheritdoc/>
        public async Task <ITextView> OpenFile(
            IPullRequestSession session,
            string relativePath,
            bool workingDirectory)
        {
            Guard.ArgumentNotNull(session, nameof(session));
            Guard.ArgumentNotEmptyString(relativePath, nameof(relativePath));

            try
            {
                var    fullPath = GetAbsolutePath(session.LocalRepository, relativePath);
                string fileName;
                string commitSha;

                if (workingDirectory)
                {
                    fileName  = fullPath;
                    commitSha = null;
                }
                else
                {
                    var file = await session.GetFile(relativePath);

                    fileName = await pullRequestService.ExtractToTempFile(
                        session.LocalRepository,
                        session.PullRequest,
                        file.RelativePath,
                        file.CommitSha,
                        pullRequestService.GetEncoding(session.LocalRepository, file.RelativePath));

                    commitSha = file.CommitSha;
                }

                IVsTextView  textView;
                IWpfTextView wpfTextView;
                using (workingDirectory ? null : OpenInProvisionalTab())
                {
                    var readOnly = !workingDirectory;
                    textView = OpenDocument(fileName, readOnly, out wpfTextView);

                    if (!workingDirectory)
                    {
                        AddBufferTag(wpfTextView.TextBuffer, session, fullPath, commitSha, null);
                        EnableNavigateToEditor(textView, session);
                    }
                }

                if (workingDirectory)
                {
                    await usageTracker.IncrementCounter(x => x.NumberOfPRDetailsOpenFileInSolution);
                }
                else
                {
                    await usageTracker.IncrementCounter(x => x.NumberOfPRDetailsViewFile);
                }

                return(wpfTextView);
            }
            catch (Exception e)
            {
                ShowErrorInStatusBar("Error opening file", e);
                return(null);
            }
        }
示例#23
0
        void EnableNavigateToEditor(ITextView textView, IPullRequestSession session)
        {
            var vsTextView = vsEditorAdaptersFactory.GetViewAdapter(textView);

            EnableNavigateToEditor(vsTextView, session);
        }
 /// <summary>
 /// Gets the head (target) branch label for a pull request, stripping the owner if the pull
 /// request is not from a fork.
 /// </summary>
 /// <param name="session">The pull request session.</param>
 /// <returns>The head branch label</returns>
 public static string GetBaseBranchDisplay(this IPullRequestSession session)
 {
     Guard.ArgumentNotNull(session, nameof(session));
     return(GetBranchDisplay(session.IsPullRequestFromFork(), session.PullRequest?.Base?.Label));
 }
示例#25
0
        /// <inheritdoc/>
        public async Task <IDifferenceViewer> OpenDiff(IPullRequestSession session, string relativePath, string headSha, bool scrollToFirstDiff)
        {
            Guard.ArgumentNotNull(session, nameof(session));
            Guard.ArgumentNotEmptyString(relativePath, nameof(relativePath));

            try
            {
                var workingDirectory = headSha == null;
                var file             = await session.GetFile(relativePath, headSha ?? "HEAD");

                var mergeBase = await pullRequestService.GetMergeBase(session.LocalRepository, session.PullRequest);

                var encoding  = pullRequestService.GetEncoding(session.LocalRepository, file.RelativePath);
                var rightFile = workingDirectory ?
                                Path.Combine(session.LocalRepository.LocalPath, relativePath) :
                                await pullRequestService.ExtractToTempFile(
                    session.LocalRepository,
                    session.PullRequest,
                    relativePath,
                    file.CommitSha,
                    encoding);

                var diffViewer = FocusExistingDiffViewer(session, mergeBase, rightFile);
                if (diffViewer != null)
                {
                    return(diffViewer);
                }

                var leftFile = await pullRequestService.ExtractToTempFile(
                    session.LocalRepository,
                    session.PullRequest,
                    relativePath,
                    mergeBase,
                    encoding);

                var leftPath = await GetBaseFileName(session, file);

                var rightPath  = file.RelativePath;
                var leftLabel  = $"{leftPath};{session.GetBaseBranchDisplay()}";
                var rightLabel = workingDirectory ? rightPath : $"{rightPath};PR {session.PullRequest.Number}";
                var caption    = $"Diff - {Path.GetFileName(file.RelativePath)}";
                var options    = __VSDIFFSERVICEOPTIONS.VSDIFFOPT_DetectBinaryFiles |
                                 __VSDIFFSERVICEOPTIONS.VSDIFFOPT_LeftFileIsTemporary;

                if (!workingDirectory)
                {
                    options |= __VSDIFFSERVICEOPTIONS.VSDIFFOPT_RightFileIsTemporary;
                }

                IVsWindowFrame frame;
                using (OpenWithOption(DifferenceViewerOptions.ScrollToFirstDiffName, scrollToFirstDiff))
                    using (OpenInProvisionalTab())
                    {
                        var tooltip = $"{leftLabel}\nvs.\n{rightLabel}";

                        // Diff window will open in provisional (right hand) tab until document is touched.
                        frame = VisualStudio.Services.DifferenceService.OpenComparisonWindow2(
                            leftFile,
                            rightFile,
                            caption,
                            tooltip,
                            leftLabel,
                            rightLabel,
                            string.Empty,
                            string.Empty,
                            (uint)options);
                    }

                diffViewer = GetDiffViewer(frame);

                var leftText  = diffViewer.LeftView.TextBuffer.CurrentSnapshot.GetText();
                var rightText = diffViewer.RightView.TextBuffer.CurrentSnapshot.GetText();
                if (leftText == string.Empty)
                {
                    // Don't show LeftView when empty.
                    diffViewer.ViewMode = DifferenceViewMode.RightViewOnly;
                }
                else if (rightText == string.Empty)
                {
                    // Don't show RightView when empty.
                    diffViewer.ViewMode = DifferenceViewMode.LeftViewOnly;
                }
                else if (leftText == rightText)
                {
                    // Don't show LeftView when no changes.
                    diffViewer.ViewMode = DifferenceViewMode.RightViewOnly;
                }

                AddBufferTag(diffViewer.LeftView.TextBuffer, session, leftPath, mergeBase, DiffSide.Left);

                if (!workingDirectory)
                {
                    AddBufferTag(diffViewer.RightView.TextBuffer, session, rightPath, file.CommitSha, DiffSide.Right);
                    EnableNavigateToEditor(diffViewer.LeftView, session);
                    EnableNavigateToEditor(diffViewer.RightView, session);
                    EnableNavigateToEditor(diffViewer.InlineView, session);
                }

                if (workingDirectory)
                {
                    await usageTracker.IncrementCounter(x => x.NumberOfPRDetailsCompareWithSolution);
                }
                else
                {
                    await usageTracker.IncrementCounter(x => x.NumberOfPRDetailsViewChanges);
                }

                return(diffViewer);
            }
            catch (Exception e)
            {
                ShowErrorInStatusBar("Error opening file", e);
                return(null);
            }
        }
示例#26
0
 /// <summary>
 /// Initializes a new instance of the <see cref="ShowInlineCommentTag"/> class.
 /// </summary>
 /// <param name="session">The pull request session.</param>
 /// <param name="lineNumber">0-based index of the inline tag</param>
 /// <param name="diffLineType">The diff type for the inline comment</param>
 public ShowInlineCommentTag(IPullRequestSession session, int lineNumber, DiffChangeType diffLineType)
     : base(session, lineNumber, diffLineType)
 {
 }
 void AddCompareBufferTag(ITextBuffer buffer, IPullRequestSession session, string path, bool isLeftBuffer)
 {
     buffer.Properties.GetOrCreateSingletonProperty(
         typeof(PullRequestTextBufferInfo),
         () => new PullRequestTextBufferInfo(session, path, isLeftBuffer));
 }
        /// <inheritdoc/>
        public async Task OpenFile(
            IPullRequestSession session,
            string relativePath,
            bool workingDirectory)
        {
            Guard.ArgumentNotNull(session, nameof(session));
            Guard.ArgumentNotEmptyString(relativePath, nameof(relativePath));

            try
            {
                var    fullPath = Path.Combine(session.LocalRepository.LocalPath, relativePath);
                string fileName;
                string commitSha;

                if (workingDirectory)
                {
                    fileName  = fullPath;
                    commitSha = null;
                }
                else
                {
                    var file = await session.GetFile(relativePath);

                    fileName = await pullRequestService.ExtractToTempFile(
                        session.LocalRepository,
                        session.PullRequest,
                        file.RelativePath,
                        file.CommitSha,
                        pullRequestService.GetEncoding(session.LocalRepository, file.RelativePath));

                    commitSha = file.CommitSha;
                }

                using (workingDirectory ? null : OpenInProvisionalTab())
                {
                    var window = VisualStudio.Services.Dte.ItemOperations.OpenFile(fileName);
                    window.Document.ReadOnly = !workingDirectory;

                    var buffer = GetBufferAt(fileName);

                    if (!workingDirectory)
                    {
                        AddBufferTag(buffer, session, fullPath, commitSha, null);

                        var textView = FindActiveView();
                        var file     = await session.GetFile(relativePath);

                        EnableNavigateToEditor(textView, session, file);
                    }
                }

                if (workingDirectory)
                {
                    await usageTracker.IncrementCounter(x => x.NumberOfPRDetailsOpenFileInSolution);
                }
                else
                {
                    await usageTracker.IncrementCounter(x => x.NumberOfPRDetailsViewFile);
                }
            }
            catch (Exception e)
            {
                ShowErrorInStatusBar("Error opening file", e);
            }
        }
 public Task InitializeAsync(
     IPullRequestSession session,
     Func<IInlineCommentThreadModel, bool> commentFilter = null)
 {
     return Task.CompletedTask;
 }
        /// <inheritdoc/>
        public async Task <IDifferenceViewer> OpenDiff(IPullRequestSession session, string relativePath, string headSha, bool scrollToFirstDraftOrDiff)
        {
            Guard.ArgumentNotNull(session, nameof(session));
            Guard.ArgumentNotEmptyString(relativePath, nameof(relativePath));

            try
            {
                var workingDirectory = headSha == null;
                var file             = await session.GetFile(relativePath, headSha ?? "HEAD");

                var mergeBase = await pullRequestService.GetMergeBase(session.LocalRepository, session.PullRequest);

                var encoding  = pullRequestService.GetEncoding(session.LocalRepository, file.RelativePath);
                var rightFile = workingDirectory ?
                                Path.Combine(session.LocalRepository.LocalPath, relativePath) :
                                await pullRequestService.ExtractToTempFile(
                    session.LocalRepository,
                    session.PullRequest,
                    relativePath,
                    file.CommitSha,
                    encoding);

                var diffViewer = FocusExistingDiffViewer(session, mergeBase, rightFile);
                if (diffViewer != null)
                {
                    return(diffViewer);
                }

                var leftFile = await pullRequestService.ExtractToTempFile(
                    session.LocalRepository,
                    session.PullRequest,
                    relativePath,
                    mergeBase,
                    encoding);

                var leftPath = await GetBaseFileName(session, file);

                var rightPath  = file.RelativePath;
                var leftLabel  = $"{leftPath};{session.GetBaseBranchDisplay()}";
                var rightLabel = workingDirectory ? rightPath : $"{rightPath};PR {session.PullRequest.Number}";
                var caption    = $"Diff - {Path.GetFileName(file.RelativePath)}";
                var options    = __VSDIFFSERVICEOPTIONS.VSDIFFOPT_DetectBinaryFiles |
                                 __VSDIFFSERVICEOPTIONS.VSDIFFOPT_LeftFileIsTemporary;
                var openThread        = (line : -1, side : DiffSide.Left);
                var scrollToFirstDiff = false;

                if (!workingDirectory)
                {
                    options |= __VSDIFFSERVICEOPTIONS.VSDIFFOPT_RightFileIsTemporary;
                }

                if (scrollToFirstDraftOrDiff)
                {
                    var(key, _) = PullRequestReviewCommentThreadViewModel.GetDraftKeys(
                        session.LocalRepository.CloneUrl.WithOwner(session.RepositoryOwner),
                        session.PullRequest.Number,
                        relativePath,
                        0);
                    var drafts = (await draftStore.GetDrafts <PullRequestReviewCommentDraft>(key)
                                  .ConfigureAwait(true))
                                 .OrderByDescending(x => x.data.UpdatedAt)
                                 .ToList();

                    if (drafts.Count > 0 && int.TryParse(drafts[0].secondaryKey, out var line))
                    {
                        openThread        = (line, drafts[0].data.Side);