예제 #1
0
        async Task Initialize()
        {
            needsInitialize = false;

            var bufferInfo = sessionManager.GetTextBufferInfo(buffer);

            if (bufferInfo != null)
            {
                session      = bufferInfo.Session;
                relativePath = bufferInfo.RelativePath;
                file         = await session.GetFile(relativePath);

                leftHandSide = bufferInfo.IsLeftComparisonBuffer;
                NotifyTagsChanged();
            }
            else
            {
                await InitializeLiveFile();

                sessionManagerSubscription = sessionManager
                                             .WhenAnyValue(x => x.CurrentSession)
                                             .Skip(1)
                                             .Subscribe(_ => ForgetWithLogging(InitializeLiveFile()));
            }
        }
예제 #2
0
        /// <summary>
        /// Initializes a new instance of the <see cref="InlineCommentThreadViewModel"/> class.
        /// </summary>
        /// <param name="commentService">The comment service</param>
        /// <param name="session">The current PR review session.</param>
        /// <param name="file">The file being commented on.</param>
        /// <param name="lineNumber">The 0-based line number in the file.</param>
        /// <param name="leftComparisonBuffer">
        ///     True if the comment is being left on the left-hand-side of a diff; otherwise false.
        /// </param>
        public NewInlineCommentThreadViewModel(ICommentService commentService,
                                               IPullRequestSession session,
                                               IPullRequestSessionFile file,
                                               int lineNumber,
                                               bool leftComparisonBuffer)
            : base(session.User)
        {
            Guard.ArgumentNotNull(session, nameof(session));
            Guard.ArgumentNotNull(file, nameof(file));

            Session              = session;
            File                 = file;
            LineNumber           = lineNumber;
            LeftComparisonBuffer = leftComparisonBuffer;

            PostComment = ReactiveCommand.CreateFromTask <string>(
                DoPostComment,
                this.WhenAnyValue(x => x.NeedsPush, x => !x));

            EditComment   = ReactiveCommand.Create <Tuple <string, string> >(_ => { });
            DeleteComment = ReactiveCommand.Create <Tuple <int, int> >(_ => { });

            var placeholder = PullRequestReviewCommentViewModel.CreatePlaceholder(session, commentService, this, CurrentUser);

            placeholder.BeginEdit.Execute().Subscribe();
            this.WhenAnyValue(x => x.NeedsPush).Subscribe(x => placeholder.IsReadOnly = x);
            Comments.Add(placeholder);

            file.WhenAnyValue(x => x.CommitSha).Subscribe(x => NeedsPush = x == null);
        }
예제 #3
0
        async Task InitializeLiveFile()
        {
            fileSubscription?.Dispose();
            fileSubscription = null;

            relativePath = sessionManager.GetRelativePath(buffer);

            if (relativePath != null)
            {
                file = await sessionManager.GetLiveFile(relativePath, view, buffer);

                var options = view.Options;
                visibleSubscription =
                    Observable.FromEventPattern <EditorOptionChangedEventArgs>(options, nameof(options.OptionChanged))
                    .Select(_ => Unit.Default)
                    .StartWith(Unit.Default)
                    .Select(x => options.GetOptionValue(InlineCommentTextViewOptions.MarginVisibleId))
                    .DistinctUntilChanged()
                    .Subscribe(VisibleChanged);
            }
            else
            {
                file = null;
            }

            NotifyTagsChanged();
        }
        public async Task Initialize()
        {
            var buffer = peekSession.TextView.TextBuffer;
            var info   = sessionManager.GetTextBufferInfo(buffer);

            if (info != null)
            {
                relativePath = info.RelativePath;
                leftBuffer   = info.IsLeftComparisonBuffer;
                file         = await info.Session.GetFile(relativePath);

                session = info.Session;
                await UpdateThread();
            }
            else
            {
                relativePath = sessionManager.GetRelativePath(buffer);
                file         = await sessionManager.GetLiveFile(relativePath, peekSession.TextView, buffer);
                await SessionChanged(sessionManager.CurrentSession);

                sessionSubscription = sessionManager.WhenAnyValue(x => x.CurrentSession)
                                      .Skip(1)
                                      .Subscribe(x => SessionChanged(x).Forget());
            }

            fileSubscription = file.WhenAnyValue(x => x.InlineCommentThreads).Subscribe(_ => UpdateThread().Forget());
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="InlineCommentThreadViewModel"/> class.
        /// </summary>
        /// <param name="session">The current PR review session.</param>
        /// <param name="file">The file being commented on.</param>
        /// <param name="lineNumber">The 0-based line number in the file.</param>
        /// <param name="leftComparisonBuffer">
        /// True if the comment is being left on the left-hand-side of a diff; otherwise false.
        /// </param>
        public NewInlineCommentThreadViewModel(
            IPullRequestSession session,
            IPullRequestSessionFile file,
            int lineNumber,
            bool leftComparisonBuffer)
            : base(session.User)
        {
            Guard.ArgumentNotNull(session, nameof(session));
            Guard.ArgumentNotNull(file, nameof(file));

            Session              = session;
            File                 = file;
            LineNumber           = lineNumber;
            LeftComparisonBuffer = leftComparisonBuffer;

            PostComment = ReactiveCommand.CreateAsyncTask(
                this.WhenAnyValue(x => x.NeedsPush, x => !x),
                DoPostComment);

            var placeholder = CommentViewModel.CreatePlaceholder(this, CurrentUser);

            placeholder.BeginEdit.Execute(null);
            this.WhenAnyValue(x => x.NeedsPush).Subscribe(x => placeholder.IsReadOnly = x);
            Comments.Add(placeholder);

            file.WhenAnyValue(x => x.CommitSha).Subscribe(x => NeedsPush = x == null);
        }
        static string GetAbsolutePath(IPullRequestSession session, IPullRequestSessionFile file)
        {
            var localPath    = session.LocalRepository.LocalPath;
            var relativePath = file.RelativePath.Replace('/', Path.DirectorySeparatorChar);

            return(Path.Combine(localPath, relativePath));
        }
예제 #7
0
        async Task <PullRequestReviewCommentThreadViewModel> CreateTarget(
            IMessageDraftStore draftStore             = null,
            IViewViewModelFactory factory             = null,
            IPullRequestSession session               = null,
            IPullRequestSessionFile file              = null,
            IEnumerable <InlineCommentModel> comments = null,
            bool newThread = false)
        {
            draftStore = draftStore ?? Substitute.For <IMessageDraftStore>();
            factory    = factory ?? CreateFactory();
            session    = session ?? CreateSession();
            file       = file ?? CreateFile();
            comments   = comments ?? CreateComments();

            var result = new PullRequestReviewCommentThreadViewModel(draftStore, factory);

            if (newThread)
            {
                await result.InitializeNewAsync(session, file, 10, DiffSide.Right, true);
            }
            else
            {
                var thread = Substitute.For <IInlineCommentThreadModel>();
                thread.Comments.Returns(comments.ToList());
                thread.LineNumber.Returns(10);

                await result.InitializeAsync(session, file, thread, true);
            }

            return(result);
        }
        async Task DoNavigateToEditor(IPullRequestSession session, IPullRequestSessionFile file)
        {
            try
            {
                if (!session.IsCheckedOut)
                {
                    ShowInfoMessage(App.Resources.NavigateToEditorNotCheckedOutInfoMessage);
                    return;
                }

                var fullPath = GetAbsolutePath(session, file);

                var activeView = FindActiveView();
                if (activeView == null)
                {
                    ShowErrorInStatusBar("Couldn't find active view");
                    return;
                }

                NavigateToEquivalentPosition(activeView, fullPath);

                await usageTracker.IncrementCounter(x => x.NumberOfPRDetailsNavigateToEditor);
            }
            catch (Exception e)
            {
                ShowErrorInStatusBar("Error navigating to editor", e);
            }
        }
예제 #9
0
        async Task Initialize()
        {
            needsInitialize = false;

            var bufferInfo = sessionManager.GetTextBufferInfo(buffer);

            if (bufferInfo != null)
            {
                session      = bufferInfo.Session;
                relativePath = bufferInfo.RelativePath;
                file         = await session.GetFile(relativePath);

                fileSubscription = file.LinesChanged.Subscribe(LinesChanged);
                side             = bufferInfo.Side ?? DiffSide.Right;
                NotifyTagsChanged();
            }
            else
            {
                await InitializeLiveFile();

                sessionManagerSubscription = sessionManager
                                             .WhenAnyValue(x => x.CurrentSession)
                                             .Skip(1)
                                             .Subscribe(_ => ForgetWithLogging(InitializeLiveFile()));
            }
        }
예제 #10
0
        public async Task Initialize()
        {
            var buffer = peekSession.TextView.TextBuffer;
            var info   = sessionManager.GetTextBufferInfo(buffer);

            if (info != null)
            {
                relativePath = info.RelativePath;
                side         = info.Side ?? DiffSide.Right;
                file         = await info.Session.GetFile(relativePath);

                session = info.Session;
                await UpdateThread();
            }
            else
            {
                relativePath = sessionManager.GetRelativePath(buffer);
                file         = await sessionManager.GetLiveFile(relativePath, peekSession.TextView, buffer);
                await SessionChanged(sessionManager.CurrentSession);

                sessionSubscription = sessionManager.WhenAnyValue(x => x.CurrentSession)
                                      .Skip(1)
                                      .Subscribe(x => SessionChanged(x).Forget());
            }

            fileSubscription?.Dispose();
            fileSubscription = file.LinesChanged.Subscribe(LinesChanged);
        }
예제 #11
0
            static IPullRequestSessionManager CreateSessionManager(IPullRequestSessionFile file)
            {
                var result = Substitute.For <IPullRequestSessionManager>();

                result.GetLiveFile("file.cs", Arg.Any <ITextView>(), Arg.Any <ITextBuffer>())
                .Returns(Task.FromResult(file));
                result.GetRelativePath(null).ReturnsForAnyArgs("file.cs");
                return(result);
            }
예제 #12
0
        async Task <string> CalculateCommitSha(
            IPullRequestSession session,
            IPullRequestSessionFile file,
            byte[] content)
        {
            var repo = session.LocalRepository;

            return(await sessionService.IsUnmodifiedAndPushed(repo, file.RelativePath, content) ?
                   await sessionService.GetTipSha(repo) : null);
        }
        async Task SessionChanged(IPullRequestSession session)
        {
            sessionSubscription?.Dispose();
            this.session = session;

            if (file != null)
            {
                file = null;
                NotifyTagsChanged();
            }

            if (session == null)
            {
                return;
            }

            relativePath = session.GetRelativePath(fullPath);

            if (relativePath == null)
            {
                return;
            }

            var snapshot = buffer.CurrentSnapshot;

            if (leftHandSide)
            {
                // If we're tagging the LHS of a diff, then the snapshot will be the base commit
                // (as you'd expect) but that means that the diff will be empty, so get the RHS
                // snapshot from the view for the comparison.
                var projection = view.TextSnapshot as IProjectionSnapshot;
                snapshot = projection?.SourceSnapshots.Count == 2 ? projection.SourceSnapshots[1] : null;
            }

            if (snapshot == null)
            {
                return;
            }

            var repository      = gitService.GetRepository(session.LocalRepository.LocalPath);
            var isContentSource = !leftHandSide && !(buffer is IProjectionBuffer);

            file = await session.GetFile(relativePath, isContentSource?this : null);

            if (file == null)
            {
                return;
            }

            sessionSubscription = file.WhenAnyValue(x => x.InlineCommentThreads)
                                  .Subscribe(_ => NotifyTagsChanged());

            NotifyTagsChanged();
        }
예제 #14
0
        void AddCommentToExistingThread(IPullRequestSessionFile file)
        {
            var newThreads  = file.InlineCommentThreads.ToList();
            var thread      = file.InlineCommentThreads.Single();
            var newComment  = CreateComment("New Comment");
            var newComments = thread.Comments.Concat(new[] { newComment }).ToList();

            thread.Comments.Returns(newComments);
            file.InlineCommentThreads.Returns(newThreads);
            RaisePropertyChanged(file, nameof(file.InlineCommentThreads));
        }
예제 #15
0
 async Task <string> GetBaseFileName(IPullRequestSession session, IPullRequestSessionFile file)
 {
     using (var changes = await pullRequestService.GetTreeChanges(
                session.LocalRepository,
                session.PullRequest))
     {
         var fileChange = changes.FirstOrDefault(x => x.Path == file.RelativePath);
         return(fileChange?.Status == LibGit2Sharp.ChangeKind.Renamed ?
                fileChange.OldPath : file.RelativePath);
     }
 }
예제 #16
0
        void AddCommentToExistingThread(IPullRequestSessionFile file)
        {
            var newThreads  = file.InlineCommentThreads.ToList();
            var thread      = file.InlineCommentThreads.Single();
            var newComment  = CreateComment("New Comment");
            var newComments = thread.Comments.Concat(new[] { newComment }).ToList();

            thread.Comments.Returns(newComments);
            file.InlineCommentThreads.Returns(newThreads);
            RaiseLinesChanged(file, Tuple.Create(thread.LineNumber, DiffSide.Right));
        }
 async Task <string> CalculateContentCommitSha(IPullRequestSessionFile file, byte[] content)
 {
     if (IsCheckedOut)
     {
         return(await service.IsUnmodifiedAndPushed(LocalRepository, file.RelativePath, content) ?
                await service.GetTipSha(LocalRepository) : null);
     }
     else
     {
         return(PullRequest.Head.Sha);
     }
 }
            static IPullRequestSessionManager CreateSessionManager(
                IPullRequestSessionFile file,
                DiffSide side)
            {
                var session = Substitute.For <IPullRequestSession>();

                session.GetFile("file.cs").Returns(file);

                var info   = new PullRequestTextBufferInfo(session, "file.cs", side);
                var result = Substitute.For <IPullRequestSessionManager>();

                result.GetTextBufferInfo(null).ReturnsForAnyArgs(info);
                return(result);
            }
예제 #19
0
            static IPullRequestSessionManager CreateSessionManager(
                IPullRequestSessionFile file,
                DiffSide side,
                string bufferInfoCommitSha = "HEAD")
            {
                var session = Substitute.For <IPullRequestSession>();

                session.GetFile("file.cs", bufferInfoCommitSha).Returns(file);

                var info   = new PullRequestTextBufferInfo(session, "file.cs", bufferInfoCommitSha, side);
                var result = Substitute.For <IPullRequestSessionManager>();

                result.CurrentSession.Returns(session);
                result.GetTextBufferInfo(null).ReturnsForAnyArgs(info);
                return(result);
            }
        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());
        }
 Task <byte[]> GetFileContent(IPullRequestSessionFile file)
 {
     if (!IsCheckedOut)
     {
         return(service.ExtractFileFromGit(
                    LocalRepository,
                    PullRequest.Number,
                    PullRequest.Head.Sha,
                    file.RelativePath));
     }
     else if (file.ContentSource != null)
     {
         return(file.ContentSource?.GetContent());
     }
     else
     {
         return(service.ReadFileAsync(Path.Combine(LocalRepository.LocalPath, file.RelativePath)));
     }
 }
예제 #22
0
        async Task InitializeLiveFile()
        {
            fileSubscription?.Dispose();
            fileSubscription = null;

            relativePath = sessionManager.GetRelativePath(buffer);

            if (relativePath != null)
            {
                var liveFile = await sessionManager.GetLiveFile(relativePath, view, buffer);

                fileSubscription = liveFile.LinesChanged.Subscribe(LinesChanged);
                file             = liveFile;
            }
            else
            {
                file = null;
            }

            NotifyTagsChanged();
        }
예제 #23
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);
        }
        void EnableNavigateToEditor(ITextView textView, IPullRequestSession session, IPullRequestSessionFile file)
        {
            var vsTextView = vsEditorAdaptersFactory.GetViewAdapter(textView);

            EnableNavigateToEditor(vsTextView, session, file);
        }
        void EnableNavigateToEditor(IVsTextView vsTextView, IPullRequestSession session, IPullRequestSessionFile file)
        {
            var commandGroup = VSConstants.CMDSETID.StandardCommandSet2K_guid;
            var commandId    = (int)VSConstants.VSStd2KCmdID.RETURN;

            new TextViewCommandDispatcher(vsTextView, commandGroup, commandId).Exec +=
                async(s, e) => await DoNavigateToEditor(session, file);

            var contextMenuCommandGroup = new Guid(Guids.guidContextMenuSetString);
            var goToCommandId           = PkgCmdIDList.openFileInSolutionCommand;

            new TextViewCommandDispatcher(vsTextView, contextMenuCommandGroup, goToCommandId).Exec +=
                async(s, e) => await DoNavigateToEditor(session, file);

            EnableNavigateStatusBarMessage(vsTextView, session);
        }
예제 #26
0
        void RaiseLinesChanged(IPullRequestSessionFile file, params Tuple <int, DiffSide>[] lineNumbers)
        {
            var subject = (Subject <IReadOnlyList <Tuple <int, DiffSide> > >)file.LinesChanged;

            subject.OnNext(lineNumbers);
        }