예제 #1
0
        /// <summary>
        /// Splits the provided segments into lines with a maximum width.
        /// </summary>
        /// <param name="context">The render context.</param>
        /// <param name="segments">The segments to split into lines.</param>
        /// <param name="maxWidth">The maximum width.</param>
        /// <returns>A list of lines.</returns>
        public static List <SegmentLine> SplitLines(RenderContext context, IEnumerable <Segment> segments, int maxWidth)
        {
            if (context is null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (segments is null)
            {
                throw new ArgumentNullException(nameof(segments));
            }

            var lines = new List <SegmentLine>();
            var line  = new SegmentLine();

            var stack = new Stack <Segment>(segments.Reverse());

            while (stack.Count > 0)
            {
                var segment = stack.Pop();

                // Does this segment make the line exceed the max width?
                if (line.CellCount(context) + segment.CellCount(context) > maxWidth)
                {
                    var diff   = -(maxWidth - (line.Length + segment.Text.Length));
                    var offset = segment.Text.Length - diff;

                    var(first, second) = segment.Split(offset);

                    line.Add(first);
                    lines.Add(line);
                    line = new SegmentLine();

                    if (second != null)
                    {
                        stack.Push(second);
                    }

                    continue;
                }

                // Does the segment contain a newline?
                if (segment.Text.ContainsExact("\n"))
                {
                    // Is it a new line?
                    if (segment.Text == "\n")
                    {
                        if (line.Length != 0 || segment.IsLineBreak)
                        {
                            lines.Add(line);
                            line = new SegmentLine();
                        }

                        continue;
                    }

                    var text = segment.Text;
                    while (text != null)
                    {
                        var parts = text.SplitLines();
                        if (parts.Length > 0)
                        {
                            if (parts[0].Length > 0)
                            {
                                line.Add(new Segment(parts[0], segment.Style));
                            }
                        }

                        if (parts.Length > 1)
                        {
                            if (line.Length > 0)
                            {
                                lines.Add(line);
                                line = new SegmentLine();
                            }

                            text = string.Concat(parts.Skip(1).Take(parts.Length - 1));
                        }
                        else
                        {
                            text = null;
                        }
                    }
                }
                else
                {
                    line.Add(segment);
                }
            }

            if (line.Count > 0)
            {
                lines.Add(line);
            }

            return(lines);
        }
예제 #2
0
        protected override IEnumerable <Segment> Render(RenderContext context, int maxWidth)
        {
            lock (_lock)
            {
                DidOverflow = false;

                if (_renderable != null)
                {
                    var segments = _renderable.Render(context, maxWidth);
                    var lines    = Segment.SplitLines(segments);

                    var shape = SegmentShape.Calculate(context, lines);
                    if (shape.Height > _console.Profile.Height)
                    {
                        if (Overflow == VerticalOverflow.Crop)
                        {
                            if (OverflowCropping == VerticalOverflowCropping.Bottom)
                            {
                                // Remove bottom lines
                                var index = Math.Min(_console.Profile.Height, lines.Count);
                                var count = lines.Count - index;
                                lines.RemoveRange(index, count);
                            }
                            else
                            {
                                // Remove top lines
                                var start = lines.Count - _console.Profile.Height;
                                lines.RemoveRange(0, start);
                            }

                            shape = SegmentShape.Calculate(context, lines);
                        }
                        else if (Overflow == VerticalOverflow.Ellipsis)
                        {
                            var ellipsisText = _console.Profile.Capabilities.Unicode ? "…" : "...";
                            var ellipsis     = new SegmentLine(((IRenderable) new Markup($"[yellow]{ellipsisText}[/]")).Render(context, maxWidth));

                            if (OverflowCropping == VerticalOverflowCropping.Bottom)
                            {
                                // Remove bottom lines
                                var index = Math.Min(_console.Profile.Height - 1, lines.Count);
                                var count = lines.Count - index;
                                lines.RemoveRange(index, count);
                                lines.Add(ellipsis);
                            }
                            else
                            {
                                // Remove top lines
                                var start = lines.Count - _console.Profile.Height;
                                lines.RemoveRange(0, start + 1);
                                lines.Insert(0, ellipsis);
                            }

                            shape = SegmentShape.Calculate(context, lines);
                        }

                        DidOverflow = true;
                    }

                    _shape = _shape == null ? shape : _shape.Value.Inflate(shape);
                    _shape.Value.Apply(context, ref lines);

                    foreach (var(_, _, last, line) in lines.Enumerate())
                    {
                        foreach (var item in line)
                        {
                            yield return(item);
                        }

                        if (!last)
                        {
                            yield return(Segment.LineBreak);
                        }
                    }

                    yield break;
                }

                _shape = null;
            }
        }