예제 #1
0
        private static IEnumerable <Segment> RenderAnnotation(TableRendererContext context, TableTitle?header, Style defaultStyle)
        {
            if (header == null)
            {
                return(Array.Empty <Segment>());
            }

            var paragraph = new Markup(header.Text.CapitalizeFirstLetter(), header.Style ?? defaultStyle)
                            .Alignment(Justify.Center)
                            .Overflow(Overflow.Ellipsis);

            // Render the paragraphs
            var segments = new List <Segment>();

            segments.AddRange(((IRenderable)paragraph).Render(context.Options, context.TableWidth));

            // Align over the whole buffer area
            Aligner.Align(context.Options, segments, context.Alignment, context.MaxWidth);

            segments.Add(Segment.LineBreak);
            return(segments);
        }
예제 #2
0
        private IEnumerable <Segment> RenderAnnotation(
            RenderContext context, TableTitle?header,
            int maxWidth, int tableWidth, Style defaultStyle)
        {
            if (header == null)
            {
                return(Array.Empty <Segment>());
            }

            var paragraph = new Markup(header.Text.Capitalize(), header.Style ?? defaultStyle)
                            .Alignment(Justify.Center)
                            .Overflow(Overflow.Ellipsis);

            var items = new List <Segment>();

            items.AddRange(((IRenderable)paragraph).Render(context, tableWidth));

            // Align over the whole buffer area
            Aligner.Align(context, items, Alignment, maxWidth);

            items.Add(Segment.LineBreak);
            return(items);
        }
예제 #3
0
        /// <inheritdoc/>
        protected override IEnumerable <Segment> Render(RenderContext context, int maxWidth)
        {
            if (context is null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            var border      = Border.GetSafeBorder((context.LegacyConsole || !context.Unicode) && UseSafeBorder);
            var borderStyle = BorderStyle ?? Style.Plain;

            var tableWidth     = maxWidth;
            var actualMaxWidth = maxWidth;

            var showBorder = Border.Visible;
            var hideBorder = !Border.Visible;
            var hasRows    = _rows.Count > 0;
            var hasFooters = _columns.Any(c => c.Footer != null);

            if (Width != null)
            {
                maxWidth = Math.Min(Width.Value, maxWidth);
            }

            maxWidth -= GetExtraWidth(includePadding: true);

            // Calculate the column and table widths
            var columnWidths = CalculateColumnWidths(context, maxWidth);

            // Update the table width.
            tableWidth = columnWidths.Sum() + GetExtraWidth(includePadding: true);
            if (tableWidth <= 0 || tableWidth > actualMaxWidth || columnWidths.Any(c => c <= 0))
            {
                return(new List <Segment>(new[] { new Segment("…", BorderStyle ?? Style.Plain) }));
            }

            var rows = new List <TableRow>();

            if (ShowHeaders)
            {
                // Add columns to top of rows
                rows.Add(new TableRow(new List <IRenderable>(_columns.Select(c => c.Header))));
            }

            // Add rows.
            rows.AddRange(_rows);

            if (hasFooters)
            {
                rows.Add(new TableRow(new List <IRenderable>(_columns.Select(c => c.Footer ?? Text.Empty))));
            }

            var result = new List <Segment>();

            result.AddRange(RenderAnnotation(context, Title, actualMaxWidth, tableWidth, _defaultHeadingStyle));

            // Iterate all rows
            foreach (var(index, firstRow, lastRow, row) in rows.Enumerate())
            {
                var cellHeight = 1;

                // Get the list of cells for the row and calculate the cell height
                var cells = new List <List <SegmentLine> >();
                foreach (var(columnIndex, _, _, (rowWidth, cell)) in columnWidths.Zip(row).Enumerate())
                {
                    var justification = _columns[columnIndex].Alignment;
                    var childContext  = context.WithJustification(justification);

                    var lines = Segment.SplitLines(context, cell.Render(childContext, rowWidth));
                    cellHeight = Math.Max(cellHeight, lines.Count);
                    cells.Add(lines);
                }

                // Show top of header?
                if (firstRow && showBorder)
                {
                    var separator = Aligner.Align(context, border.GetColumnRow(TablePart.Top, columnWidths, _columns), Alignment, actualMaxWidth);
                    result.Add(new Segment(separator, borderStyle));
                    result.Add(Segment.LineBreak);
                }

                // Show footer separator?
                if (ShowFooters && lastRow && showBorder && hasFooters)
                {
                    var textBorder = border.GetColumnRow(TablePart.FooterSeparator, columnWidths, _columns);
                    if (!string.IsNullOrEmpty(textBorder))
                    {
                        var separator = Aligner.Align(context, textBorder, Alignment, actualMaxWidth);
                        result.Add(new Segment(separator, borderStyle));
                        result.Add(Segment.LineBreak);
                    }
                }

                // Make cells the same shape
                cells = Segment.MakeSameHeight(cellHeight, cells);

                // Iterate through each cell row
                foreach (var cellRowIndex in Enumerable.Range(0, cellHeight))
                {
                    var rowResult = new List <Segment>();

                    foreach (var(cellIndex, firstCell, lastCell, cell) in cells.Enumerate())
                    {
                        if (firstCell && showBorder)
                        {
                            // Show left column edge
                            var part = firstRow && ShowHeaders ? TableBorderPart.HeaderLeft : TableBorderPart.CellLeft;
                            rowResult.Add(new Segment(border.GetPart(part), borderStyle));
                        }

                        // Pad column on left side.
                        if (showBorder || IsGrid)
                        {
                            var leftPadding = _columns[cellIndex].Padding.GetLeftSafe();
                            if (leftPadding > 0)
                            {
                                rowResult.Add(new Segment(new string(' ', leftPadding)));
                            }
                        }

                        // Add content
                        rowResult.AddRange(cell[cellRowIndex]);

                        // Pad cell content right
                        var length = cell[cellRowIndex].Sum(segment => segment.CellCount(context));
                        if (length < columnWidths[cellIndex])
                        {
                            rowResult.Add(new Segment(new string(' ', columnWidths[cellIndex] - length)));
                        }

                        // Pad column on the right side
                        if (showBorder || (hideBorder && !lastCell) || (hideBorder && lastCell && IsGrid && PadRightCell))
                        {
                            var rightPadding = _columns[cellIndex].Padding.GetRightSafe();
                            if (rightPadding > 0)
                            {
                                rowResult.Add(new Segment(new string(' ', rightPadding)));
                            }
                        }

                        if (lastCell && showBorder)
                        {
                            // Add right column edge
                            var part = firstRow && ShowHeaders ? TableBorderPart.HeaderRight : TableBorderPart.CellRight;
                            rowResult.Add(new Segment(border.GetPart(part), borderStyle));
                        }
                        else if (showBorder)
                        {
                            // Add column separator
                            var part = firstRow && ShowHeaders ? TableBorderPart.HeaderSeparator : TableBorderPart.CellSeparator;
                            rowResult.Add(new Segment(border.GetPart(part), borderStyle));
                        }
                    }

                    // Align the row result.
                    Aligner.Align(context, rowResult, Alignment, actualMaxWidth);

                    // Is the row larger than the allowed max width?
                    if (Segment.CellCount(context, rowResult) > actualMaxWidth)
                    {
                        result.AddRange(Segment.Truncate(context, rowResult, actualMaxWidth));
                    }
                    else
                    {
                        result.AddRange(rowResult);
                    }

                    result.Add(Segment.LineBreak);
                }

                // Show header separator?
                if (firstRow && showBorder && ShowHeaders && hasRows)
                {
                    var separator = Aligner.Align(context, border.GetColumnRow(TablePart.HeaderSeparator, columnWidths, _columns), Alignment, actualMaxWidth);
                    result.Add(new Segment(separator, borderStyle));
                    result.Add(Segment.LineBreak);
                }

                // Show bottom of footer?
                if (lastRow && showBorder)
                {
                    var separator = Aligner.Align(context, border.GetColumnRow(TablePart.Bottom, columnWidths, _columns), Alignment, actualMaxWidth);
                    result.Add(new Segment(separator, borderStyle));
                    result.Add(Segment.LineBreak);
                }
            }

            result.AddRange(RenderAnnotation(context, Caption, actualMaxWidth, tableWidth, _defaultCaptionStyle));

            return(result);
        }
예제 #4
0
        public static List <Segment> Render(TableRendererContext context, List <int> columnWidths)
        {
            // Can't render the table?
            if (context.TableWidth <= 0 || context.TableWidth > context.MaxWidth || columnWidths.Any(c => c <= 0))
            {
                return(new List <Segment>(new[] { new Segment("…", context.BorderStyle ?? Style.Plain) }));
            }

            var result = new List <Segment>();

            result.AddRange(RenderAnnotation(context, context.Title, _defaultHeadingStyle));

            // Iterate all rows
            foreach (var(index, isFirstRow, isLastRow, row) in context.Rows.Enumerate())
            {
                var cellHeight = 1;

                // Get the list of cells for the row and calculate the cell height
                var cells = new List <List <SegmentLine> >();
                foreach (var(columnIndex, _, _, (rowWidth, cell)) in columnWidths.Zip(row).Enumerate())
                {
                    var justification = context.Columns[columnIndex].Alignment;
                    var childContext  = context.Options.WithJustification(justification);

                    var lines = Segment.SplitLines(context.Options, cell.Render(childContext, rowWidth));
                    cellHeight = Math.Max(cellHeight, lines.Count);
                    cells.Add(lines);
                }

                // Show top of header?
                if (isFirstRow && context.ShowBorder)
                {
                    var separator = Aligner.Align(context.Options, context.Border.GetColumnRow(TablePart.Top, columnWidths, context.Columns), context.Alignment, context.MaxWidth);
                    result.Add(new Segment(separator, context.BorderStyle));
                    result.Add(Segment.LineBreak);
                }

                // Show footer separator?
                if (context.ShowFooters && isLastRow && context.ShowBorder && context.HasFooters)
                {
                    var textBorder = context.Border.GetColumnRow(TablePart.FooterSeparator, columnWidths, context.Columns);
                    if (!string.IsNullOrEmpty(textBorder))
                    {
                        var separator = Aligner.Align(context.Options, textBorder, context.Alignment, context.MaxWidth);
                        result.Add(new Segment(separator, context.BorderStyle));
                        result.Add(Segment.LineBreak);
                    }
                }

                // Make cells the same shape
                cells = Segment.MakeSameHeight(cellHeight, cells);

                // Iterate through each cell row
                foreach (var cellRowIndex in Enumerable.Range(0, cellHeight))
                {
                    var rowResult = new List <Segment>();

                    foreach (var(cellIndex, isFirstCell, isLastCell, cell) in cells.Enumerate())
                    {
                        if (isFirstCell && context.ShowBorder)
                        {
                            // Show left column edge
                            var part = isFirstRow && context.ShowHeaders ? TableBorderPart.HeaderLeft : TableBorderPart.CellLeft;
                            rowResult.Add(new Segment(context.Border.GetPart(part), context.BorderStyle));
                        }

                        // Pad column on left side.
                        if (context.ShowBorder || context.IsGrid)
                        {
                            var leftPadding = context.Columns[cellIndex].Padding.GetLeftSafe();
                            if (leftPadding > 0)
                            {
                                rowResult.Add(new Segment(new string(' ', leftPadding)));
                            }
                        }

                        // Add content
                        rowResult.AddRange(cell[cellRowIndex]);

                        // Pad cell content right
                        var length = cell[cellRowIndex].Sum(segment => segment.CellCount(context.Options));
                        if (length < columnWidths[cellIndex])
                        {
                            rowResult.Add(new Segment(new string(' ', columnWidths[cellIndex] - length)));
                        }

                        // Pad column on the right side
                        if (context.ShowBorder || (context.HideBorder && !isLastCell) || (context.HideBorder && isLastCell && context.IsGrid && context.PadRightCell))
                        {
                            var rightPadding = context.Columns[cellIndex].Padding.GetRightSafe();
                            if (rightPadding > 0)
                            {
                                rowResult.Add(new Segment(new string(' ', rightPadding)));
                            }
                        }

                        if (isLastCell && context.ShowBorder)
                        {
                            // Add right column edge
                            var part = isFirstRow && context.ShowHeaders ? TableBorderPart.HeaderRight : TableBorderPart.CellRight;
                            rowResult.Add(new Segment(context.Border.GetPart(part), context.BorderStyle));
                        }
                        else if (context.ShowBorder)
                        {
                            // Add column separator
                            var part = isFirstRow && context.ShowHeaders ? TableBorderPart.HeaderSeparator : TableBorderPart.CellSeparator;
                            rowResult.Add(new Segment(context.Border.GetPart(part), context.BorderStyle));
                        }
                    }

                    // Align the row result.
                    Aligner.Align(context.Options, rowResult, context.Alignment, context.MaxWidth);

                    // Is the row larger than the allowed max width?
                    if (Segment.CellCount(context.Options, rowResult) > context.MaxWidth)
                    {
                        result.AddRange(Segment.Truncate(context.Options, rowResult, context.MaxWidth));
                    }
                    else
                    {
                        result.AddRange(rowResult);
                    }

                    result.Add(Segment.LineBreak);
                }

                // Show header separator?
                if (isFirstRow && context.ShowBorder && context.ShowHeaders && context.HasRows)
                {
                    var separator = Aligner.Align(context.Options, context.Border.GetColumnRow(TablePart.HeaderSeparator, columnWidths, context.Columns), context.Alignment, context.MaxWidth);
                    result.Add(new Segment(separator, context.BorderStyle));
                    result.Add(Segment.LineBreak);
                }

                // Show bottom of footer?
                if (isLastRow && context.ShowBorder)
                {
                    var separator = Aligner.Align(context.Options, context.Border.GetColumnRow(TablePart.Bottom, columnWidths, context.Columns), context.Alignment, context.MaxWidth);
                    result.Add(new Segment(separator, context.BorderStyle));
                    result.Add(Segment.LineBreak);
                }
            }

            result.AddRange(RenderAnnotation(context, context.Caption, _defaultCaptionStyle));
            return(result);
        }