public ChangeInLinesInfo GetChangeInLines(IReadOnlyList <VisualTextLine> lines, TextRange range)
        {
            var orderedRanges = (new[] { range.StartPosition, range.EndPosition }).OrderBy(elem => elem.Line).ThenBy(elem => elem.Column).ToArray();
            var pair          = new TextRange {
                StartPosition = orderedRanges[0],
                EndPosition   = orderedRanges[1]
            };
            var rangeEnd = -1;

            if (pair.StartPosition.Line == pair.EndPosition.Line)
            {
                rangeEnd = pair.EndPosition.Line;
            }
            else
            {
                rangeEnd = pair.EndPosition.Line + 1;
            }

            var firstPart  = Cut(lines[pair.StartPosition.Line], 0, pair.StartPosition.Column);
            var secondPart = Cut(lines[pair.EndPosition.Line], pair.EndPosition.Column);

            return(new ChangeInLinesInfo {
                LinesToChange = new Dictionary <TextPosition, VisualTextLine> {
                    [new TextPosition(pair.StartPosition.Column, pair.StartPosition.Line)] =
                        VisualTextLine.MergeLines(new[] { firstPart, secondPart }, firstPart.Index)
                },
                LinesToRemove = Enumerable.Range(pair.StartPosition.Line, rangeEnd).ToList()
            });
        }
        private ChangeInLinesInfo DeleteFromActiveLine(IReadOnlyList <VisualTextLine> lines, TextPosition startingTextPosition)
        {
            var currentLine     = lines[startingTextPosition.Line];
            var firstPart       = Cut(currentLine, 0, startingTextPosition.Column);
            var secondPart      = Cut(currentLine, startingTextPosition.Column + 1);
            var lineAfterRemove = VisualTextLine.MergeLines(new[] { firstPart, secondPart }, currentLine.Index);

            return(new ChangeInLinesInfo {
                LinesToChange = new Dictionary <TextPosition, VisualTextLine> {
                    [new TextPosition(startingTextPosition.Column, startingTextPosition.Line)] = lineAfterRemove
                },
                LinesToRemove = new int[0]
            });
        }
        private ChangeInLinesInfo RemoveFromActiveLine(IReadOnlyList <VisualTextLine> lines, TextPosition startingTextPosition)
        {
            var currentLine     = lines[startingTextPosition.Line];
            var attachRest      = startingTextPosition.Column < lines[startingTextPosition.Line].Length;
            var firstPart       = Cut(currentLine, 0, startingTextPosition.Column - 1);
            var secondPart      = attachRest ? Cut(currentLine, startingTextPosition.Column) : null;
            var lineAfterRemove = secondPart != null?VisualTextLine.MergeLines(new[] { firstPart, secondPart }, currentLine.Index) : firstPart;

            return(new ChangeInLinesInfo {
                LinesToChange = new Dictionary <TextPosition, VisualTextLine> {
                    [new TextPosition(startingTextPosition.Column - 1, startingTextPosition.Line)] = lineAfterRemove
                },
                LinesToRemove = new int[0]
            });
        }
        private ChangeInLinesInfo RemoveThisLine(IReadOnlyList <VisualTextLine> lines, TextPosition startingTextPosition)
        {
            var firstLine     = lines[startingTextPosition.Line - 1];
            var linesAffected = new List <KeyValuePair <TextPosition, VisualTextLine> > {
                new KeyValuePair <TextPosition, VisualTextLine>(
                    new TextPosition(lines[startingTextPosition.Line - 1].Length, startingTextPosition.Line - 1),
                    VisualTextLine.MergeLines(new[] { firstLine, lines[startingTextPosition.Line] }, firstLine.Index))
            };

            for (var i = startingTextPosition.Line + 1; i < lines.Count; i++)
            {
                linesAffected.Add(new KeyValuePair <TextPosition, VisualTextLine>(new TextPosition(0, i - 1), lines[i].CloneWithIndexChange(i - 1)));
            }

            return(new ChangeInLinesInfo {
                LinesToChange = linesAffected,
                LinesToRemove = new[] { lines.Count - 1 }
            });
        }
        private ChangeInLinesInfo DeleteNextLine(IReadOnlyList <VisualTextLine> lines, TextPosition startingTextPosition)
        {
            var firstLine     = lines[startingTextPosition.Line];
            var secondLine    = startingTextPosition.Line + 1 < lines.Count ? lines[startingTextPosition.Line + 1] : null;
            var linesToMerge  = secondLine == null ? new[] { firstLine } : new[] { firstLine, secondLine };
            var linesAffected = new List <KeyValuePair <TextPosition, VisualTextLine> > {
                new KeyValuePair <TextPosition, VisualTextLine>(
                    new TextPosition(startingTextPosition.Column, startingTextPosition.Line),
                    VisualTextLine.MergeLines(linesToMerge, firstLine.Index))
            };

            for (var i = startingTextPosition.Line + 2; i < lines.Count; i++)
            {
                linesAffected.Add(new KeyValuePair <TextPosition, VisualTextLine>(new TextPosition(0, i - 1), lines[i].CloneWithIndexChange(i - 1)));
            }

            return(new ChangeInLinesInfo {
                LinesToChange = linesAffected,
                LinesToRemove = new[] { lines.Count - 1 }
            });
        }