public bool MoveSelectedLinesUp()

in src/Editor/Text/Impl/EditorOperations/EditorOperations.cs [127:337]


        public bool MoveSelectedLinesUp()
        {
            Func<bool> action = () =>
            {
                bool success = false;

                // find line start
                ITextViewLine startViewLine = GetLineStart(_textView, _textView.Selection.Start.Position);
                SnapshotPoint start = startViewLine.Start;
                ITextSnapshotLine startLine = start.GetContainingLine();

                // find the last line view
                ITextViewLine endViewLine = GetLineEnd(_textView, _textView.Selection.End.Position);
                SnapshotPoint end = endViewLine.EndIncludingLineBreak;
                ITextSnapshotLine endLine = endViewLine.End.GetContainingLine();

                ITextSnapshot snapshot = endLine.Snapshot;

                // Handle the case where multiple lines are selected and the caret is sitting just after the line break on the next line.
                // Shortening the selection here handles the case where the last line is a collapsed region. Using endLine.End will give
                // a line within the collapsed region instead of skipping it all together. 
                if (GetLineEnd(_textView, startViewLine.Start) != endViewLine
                    && _textView.Selection.End.Position == GetLineStart(_textView, _textView.Selection.End.Position).Start
                    && !_textView.Selection.End.IsInVirtualSpace)
                {
                    endLine = snapshot.GetLineFromLineNumber(endLine.LineNumber - 1);
                    end = endLine.EndIncludingLineBreak;
                    endViewLine = _textView.GetTextViewLineContainingBufferPosition(_textView.Selection.End.Position - 1);
                }

                #region Initial Asserts

                Debug.Assert(_textView.Selection.Start.Position.Snapshot == _textView.TextSnapshot, "Selection is out of sync with view.");

                Debug.Assert(_textView.TextSnapshot == _textView.TextBuffer.CurrentSnapshot, "View is out of sync with text buffer.");

                Debug.Assert(_textView.TextSnapshot == snapshot, "Text view lines are out of sync with the view");

                #endregion

                // check if we are at the top of the file, or trying to move a blank line
                if (startLine.LineNumber < 1 || start == end)
                {
                    // noop 
                    success = true;
                }
                else
                {
                    // find the line we are going to move over
                    ITextSnapshotLine prevLine = snapshot.GetLineFromLineNumber(startLine.LineNumber - 1);

                    // prevLineExtent is different from prevLine.Extent and avoids issues around collapsed regions
                    SnapshotPoint prevLineStart = GetLineStart(_textView, prevLine.Start).Start;
                    SnapshotSpan prevLineExtent = new SnapshotSpan(prevLineStart, prevLine.End);
                    SnapshotSpan prevLineExtentIncludingLineBreak = new SnapshotSpan(prevLineStart, prevLine.EndIncludingLineBreak);

                    using (ITextEdit edit = _textView.TextBuffer.CreateEdit())
                    {
                        int offset;

                        SnapshotSpan curLineExtent = new SnapshotSpan(startViewLine.Start, endViewLine.End);
                        SnapshotSpan curLineExtentIncLineBreak = new SnapshotSpan(startViewLine.Start, endViewLine.EndIncludingLineBreak);
                        string curLineText = curLineExtentIncLineBreak.GetText();

                        List<Tuple<Span, IOutliningRegionTag>> collapsedSpansInCurLine = null;
                        bool hasCollapsedRegions = false;

                        IOutliningManager outliningManager = (_factory.OutliningManagerService != null)
                                                             ? _factory.OutliningManagerService.GetOutliningManager(_textView)
                                                             : null;

                        if (outliningManager != null)
                        {
                            collapsedSpansInCurLine = outliningManager.GetCollapsedRegions(new NormalizedSnapshotSpanCollection(curLineExtent))
                                .Select(collapsed => Tuple.Create(collapsed.Extent.GetSpan(curLineExtent.Snapshot).Span, collapsed.Tag)).ToList();

                            hasCollapsedRegions = collapsedSpansInCurLine.Count > 0;

                            // check if we have collapsed spans in the selection and add the undo primitive if so
                            if (hasCollapsedRegions)
                            {
                                using (ITextUndoTransaction undoTransaction = _undoHistory.CreateTransaction(Strings.MoveSelLinesUp))
                                {
                                    BeforeCollapsedMoveUndoPrimitive undoPrim = new BeforeCollapsedMoveUndoPrimitive(outliningManager, _textView, collapsedSpansInCurLine);
                                    undoTransaction.AddUndo(undoPrim);
                                    undoTransaction.Complete();
                                }
                            }
                        }

                        string nextLineText = prevLineExtentIncludingLineBreak.GetText();

                        offset = nextLineText.Length;

                        // make the change
                        edit.Delete(curLineExtentIncLineBreak);
                        edit.Insert(prevLineExtentIncludingLineBreak.Start, curLineText);

                        // swap the line break around if needed for the last line of the selection                    
                        if (endViewLine.LineBreakLength == 0 && endViewLine.EndIncludingLineBreak == snapshot.Length)
                        {
                            // put the line break on the line we just moved that didn't have one
                            edit.Insert(prevLine.ExtentIncludingLineBreak.Start, prevLine.GetLineBreakText());

                            // delete the break from the line now at the end of the file
                            edit.Delete(new SnapshotSpan(prevLine.End, prevLine.EndIncludingLineBreak));
                        }


                        if (!edit.HasFailedChanges)
                        {
                            // store the position before the edit is applied
                            int anchorPos = _textView.Selection.AnchorPoint.Position.Position;
                            int anchorVirtualSpace = _textView.Selection.AnchorPoint.VirtualSpaces;
                            int activePos = _textView.Selection.ActivePoint.Position.Position;
                            int activeVirtualSpace = _textView.Selection.ActivePoint.VirtualSpaces;
                            var selectionMode = _textView.Selection.Mode;

                            // apply the edit
                            ITextSnapshot newSnapshot = edit.Apply();

                            if (newSnapshot != snapshot)
                            {

                                // Update the selection and caret position after the move
                                ITextSnapshot currentSnapshot = snapshot.TextBuffer.CurrentSnapshot;
                                VirtualSnapshotPoint desiredAnchor = new VirtualSnapshotPoint(
                                    new SnapshotPoint(newSnapshot, Math.Min(anchorPos - offset, newSnapshot.Length)), anchorVirtualSpace)
                                    .TranslateTo(currentSnapshot, PointTrackingMode.Negative);
                                VirtualSnapshotPoint desiredActive = new VirtualSnapshotPoint(
                                    new SnapshotPoint(newSnapshot, Math.Min(activePos - offset, newSnapshot.Length)), activeVirtualSpace)
                                    .TranslateTo(currentSnapshot, PointTrackingMode.Negative);

                                // Keep the selection and caret position the same
                                SelectAndMoveCaret(desiredAnchor, desiredActive, selectionMode, EnsureSpanVisibleOptions.None);

                                // Recollapse the spans
                                if (outliningManager != null && hasCollapsedRegions)
                                {
                                    // This comes from adhocoutliner.cs in env\editor\pkg\impl\outlining and will not be available outside of VS
                                    SimpleTagger<IOutliningRegionTag> simpleTagger =
                                        _textView.TextBuffer.Properties.GetOrCreateSingletonProperty<SimpleTagger<IOutliningRegionTag>>(
                                        () => new SimpleTagger<IOutliningRegionTag>(_textView.TextBuffer));

                                    if (simpleTagger != null)
                                    {
                                        if (hasCollapsedRegions)
                                        {
                                            List<Tuple<ITrackingSpan, IOutliningRegionTag>> addedSpans = collapsedSpansInCurLine.Select(tuple => Tuple.Create(newSnapshot.CreateTrackingSpan(tuple.Item1.Start - offset, tuple.Item1.Length,
                                                SpanTrackingMode.EdgeExclusive), tuple.Item2)).ToList();

                                            if (addedSpans.Count > 0)
                                            {
                                                List<Tuple<Span, IOutliningRegionTag>> spansForUndo = new List<Tuple<Span, IOutliningRegionTag>>();

                                                foreach (var addedSpan in addedSpans)
                                                {
                                                    simpleTagger.CreateTagSpan(addedSpan.Item1, addedSpan.Item2);
                                                    spansForUndo.Add(new Tuple<Span, IOutliningRegionTag>(addedSpan.Item1.GetSpan(newSnapshot), addedSpan.Item2));
                                                }

                                                SnapshotSpan changedSpan = new SnapshotSpan(addedSpans.Select(tuple => tuple.Item1.GetSpan(newSnapshot).Start).Min(),
                                                    addedSpans.Select(tuple => tuple.Item1.GetSpan(newSnapshot).End).Max());

                                                List<SnapshotSpan> addedSnapshotSpans = addedSpans.Select(tuple => tuple.Item1.GetSpan(newSnapshot)).ToList();


                                                bool disableOutliningUndo = _editorOptions.IsOutliningUndoEnabled();

                                                // Recollapse the spans
                                                // We need to disable the OutliningUndoManager for this operation otherwise an undo will expand it
                                                try
                                                {
                                                    if (disableOutliningUndo)
                                                    {
                                                        _textView.Options.SetOptionValue(DefaultTextViewOptions.OutliningUndoOptionId, false);
                                                    }

                                                    outliningManager.CollapseAll(changedSpan, collapsible => addedSnapshotSpans.Contains(collapsible.Extent.GetSpan(newSnapshot)));
                                                }
                                                finally
                                                {
                                                    if (disableOutliningUndo)
                                                    {
                                                        _textView.Options.SetOptionValue(DefaultTextViewOptions.OutliningUndoOptionId, true);
                                                    }
                                                }

                                                // we need to recollapse after a redo
                                                using (ITextUndoTransaction undoTransaction = _undoHistory.CreateTransaction(Strings.MoveSelLinesUp))
                                                {
                                                    AfterCollapsedMoveUndoPrimitive undoPrim = new AfterCollapsedMoveUndoPrimitive(outliningManager, _textView, spansForUndo);
                                                    undoTransaction.AddUndo(undoPrim);
                                                    undoTransaction.Complete();
                                                }
                                            }
                                        }
                                    }
                                }

                                success = true;
                            }
                        }
                    }
                }

                return success;
            };

            return ExecuteAction(Strings.MoveSelLinesUp, action, SelectionUpdate.Ignore, true);
        }