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())); } }
/// <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); }
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)); }
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); } }
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())); } }
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); }
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); }
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(); }
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)); }
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); } }
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); }
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))); } }
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(); }
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); }
void RaiseLinesChanged(IPullRequestSessionFile file, params Tuple <int, DiffSide>[] lineNumbers) { var subject = (Subject <IReadOnlyList <Tuple <int, DiffSide> > >)file.LinesChanged; subject.OnNext(lineNumbers); }