/// <summary>
        /// Calculate tab offsets by going up
        /// </summary>
        private void CalculateTabOffsetUp(ITextSnapshotLine curLine, int colNumber, ColumnSizeInfo colTabOffset)
        {
            int curLineNumber = curLine.LineNumber - 1;

            ITextSnapshot textSnapshot = _textView.TextSnapshot;

            ElasticTabstopsLine elasticLine = _elasticTabstopsLinesCache[curLine.LineNumber];
            bool isLastColumnInLine         = elasticLine.IsLastColumnInLine(colNumber);

            while (curLineNumber >= 0)
            {
                ITextSnapshotLine   upLine        = textSnapshot.GetLineFromLineNumber(curLineNumber);
                ElasticTabstopsLine upElasticLine = GetElasticTabstopsLine(upLine);

                if (upElasticLine.IsLastColumnInLine(colNumber) != isLastColumnInLine)
                {
                    break;
                }

                ElasticTabstopsColumn upColumn = upElasticLine.GetColumnOrDefault(colNumber);

                if (upColumn == null)
                {
                    break;
                }

                upColumn.TabOffset = colTabOffset;
                ShrinkTabOffset(upElasticLine, colNumber);
                curLineNumber--;
            }
        }
        /// <summary>
        /// Calculate tab offsets by going down
        /// </summary>
        private void CalculateTabOffsetDown(ITextSnapshotLine curLine, int colNumber, ColumnSizeInfo colTabOffset)
        {
            int curLineNumber = curLine.LineNumber + 1;

            ITextSnapshot textSnapshot = _textView.TextSnapshot;

            ElasticTabstopsLine elasticLine = _elasticTabstopsLinesCache[curLine.LineNumber];
            bool isLastColumnInLine         = elasticLine.IsLastColumnInLine(colNumber);

            while (curLineNumber < textSnapshot.LineCount)
            {
                ITextSnapshotLine   downLine        = textSnapshot.GetLineFromLineNumber(curLineNumber);
                ElasticTabstopsLine downElasticLine = GetElasticTabstopsLine(downLine);

                if (downElasticLine.IsLastColumnInLine(colNumber) != isLastColumnInLine)
                {
                    break;
                }

                ElasticTabstopsColumn downColumn = downElasticLine.GetColumnOrDefault(colNumber);

                if (downColumn == null)
                {
                    break;
                }

                downColumn.TabOffset = colTabOffset;
                ShrinkTabOffset(downElasticLine, colNumber);
                curLineNumber++;
            }
        }
        /// <summary>
        /// Fix tab offset for a column if needed
        /// </summary>
        private void ShrinkTabOffset(ElasticTabstopsLine tabLine, int colNumber)
        {
            ElasticTabstopsColumn colTabOffset = tabLine.ElasticColumns[colNumber];

            double width = CalculateInitialWidth(tabLine, colNumber);

            if (colTabOffset.TabOffset.ColumnWidth < width)
            {
                colTabOffset.TabOffset.ColumnWidth = width;
                colTabOffset.TabOffset.TabOffset   = CalculateInitialTabOffset(tabLine, colNumber);
            }
        }
            /// <summary>
            /// Returns true if column contains changed, false otherwise
            /// </summary>
            internal bool ChangedRegardingTo(ElasticTabstopsColumn elasticTabstopsColumn)
            {
                if (this == elasticTabstopsColumn)
                {
                    return(false);
                }

                if (ColumnTextLength != elasticTabstopsColumn.ColumnTextLength)
                {
                    return(true);
                }

                return(TabOffset.ChangedRegardingTo(elasticTabstopsColumn.TabOffset));
            }
        /// <summary>
        /// Calculates column width for a specific column in specific line
        /// </summary>
        private double CalculateInitialWidth(ElasticTabstopsLine elasticLine, int colNumber)
        {
            ITextSnapshot         textSnapshot = _textView.TextSnapshot;
            ElasticTabstopsColumn column       = elasticLine.ElasticColumns[colNumber];
            Span span = new Span(column.Start, column.ColumnTextLength);

            if (span.Start > textSnapshot.Length || span.End > textSnapshot.Length)
            {
                return(0);
            }

            SnapshotSpan columnSpan = new SnapshotSpan(textSnapshot, span);

            double columnWidth = _textMeasureService.GetWidth(columnSpan);

            return(Math.Max(columnWidth, _minCellWidth));
        }
        /// <summary>
        /// Calculate tab offsets for line in a given direction
        /// </summary>
        private void CalculateTabOffsets(ITextSnapshotLine line, CalculateDirection direction, bool forceInvalidate)
        {
            //Calculates tab offset for a given line for the given direction
            ElasticTabstopsLine elasticLine = GetElasticTabstopsLine(line, forceInvalidate);

            for (int colNumber = 0; colNumber < elasticLine.ElasticColumns.Length; colNumber++)
            {
                ElasticTabstopsColumn column = elasticLine.ElasticColumns[colNumber];

                //Tab offset is allready calculated during other line calculation
                if (!forceInvalidate && column.TabOffset != null)
                {
                    continue;
                }

                //Assign the same ColumnTabOffset to all columns in the same block
                ColumnSizeInfo colTabOffset = new ColumnSizeInfo
                {
                    TabOffset   = CalculateInitialTabOffset(elasticLine, colNumber),
                    ColumnWidth = CalculateInitialWidth(elasticLine, colNumber)
                };

                column.TabOffset = colTabOffset;

                switch (direction)
                {
                case CalculateDirection.Up:
                    CalculateTabOffsetUp(line, colNumber, colTabOffset);
                    break;

                case CalculateDirection.Down:
                    CalculateTabOffsetDown(line, colNumber, colTabOffset);
                    break;

                case CalculateDirection.DownUp:
                    CalculateTabOffsetDown(line, colNumber, colTabOffset);
                    CalculateTabOffsetUp(line, colNumber, colTabOffset);
                    break;

                default:
                    throw new ArgumentException("direction");
                }
            }
        }
        /// <summary>
        /// Returns ElasticTabstopsLine with initialized ElasticColumns
        /// </summary>
        private ElasticTabstopsLine GetElasticTabstopsLine(ITextSnapshotLine line, bool forceInvalidateColumns = false)
        {
            ElasticTabstopsLine elasticTabstopsLine = _elasticTabstopsLinesCache[line.LineNumber];

            if (elasticTabstopsLine.ElasticColumns == null || forceInvalidateColumns)
            {
                string   lineText  = line.GetText();
                string[] tabSplits = lineText.Split('\t');
                elasticTabstopsLine.ElasticColumns = new ElasticTabstopsColumn[tabSplits.Length];
                int curPosInLine = line.Start.Position;
                for (int i = 0; i < tabSplits.Length; i++)
                {
                    string ts = tabSplits[i];
                    ElasticTabstopsColumn column = new ElasticTabstopsColumn {
                        ColumnTextLength = ts.Length, Start = curPosInLine
                    };
                    //skeep tab
                    curPosInLine += ts.Length + 1;
                    elasticTabstopsLine.ElasticColumns[i] = column;
                }
            }
            return(elasticTabstopsLine);
        }