From d9ee24460c342cdae2ca3fef6a95c8af0f53acf4 Mon Sep 17 00:00:00 2001 From: Balki Date: Sun, 22 Feb 2026 04:15:03 +0000 Subject: [PATCH] Add unicode printing support for barred output (#1984) --- pkg/cli/option_parse.go | 10 ++++ pkg/cli/option_types.go | 1 + pkg/output/record_writer_pprint.go | 93 ++++++++++++++++++++++-------- 3 files changed, 81 insertions(+), 23 deletions(-) diff --git a/pkg/cli/option_parse.go b/pkg/cli/option_parse.go index 517f84962..782f3a7f5 100644 --- a/pkg/cli/option_parse.go +++ b/pkg/cli/option_parse.go @@ -540,6 +540,16 @@ var PPRINTOnlyFlagSection = FlagSection{ }, }, + { + name: "--barred-unicode", + help: "Uses unicode printing chars for barred output", + parser: func(args []string, argc int, pargi *int, options *TOptions) { + options.WriterOptions.BarredPprintOutput = true + options.WriterOptions.BarredUseUnicode = true + *pargi += 1 + }, + }, + { name: "--barred-input", help: "When used in conjunction with --pprint, accepts barred input.", diff --git a/pkg/cli/option_types.go b/pkg/cli/option_types.go index 9924382d7..4a2761e5f 100644 --- a/pkg/cli/option_types.go +++ b/pkg/cli/option_types.go @@ -96,6 +96,7 @@ type TWriterOptions struct { HeaderlessOutput bool BarredPprintOutput bool + BarredUseUnicode bool RightAlignedPPRINTOutput bool RightAlignedXTABOutput bool diff --git a/pkg/output/record_writer_pprint.go b/pkg/output/record_writer_pprint.go index 93b546b27..29c599ba1 100644 --- a/pkg/output/record_writer_pprint.go +++ b/pkg/output/record_writer_pprint.go @@ -228,6 +228,22 @@ func (writer *RecordWriterPPRINT) writeHeterogenousListNonBarred( // | wye | pan | 5 | 0.5732889198020006 | 0.8636244699032729 | // +-----+-----+----+----------------------+---------------------+ +type barredChars struct { + horizontalStart string + horizontalMiddle string + horizontalEnd string + horizontalBar string + verticalStart string + verticalMiddle string + verticalEnd string + firstRowHorizontalStart string + firstRowHorizontalMiddle string + firstRowHorizontalEnd string + lastRowHorizontalStart string + lastRowHorizontalMiddle string + lastRowHorizontalEnd string +} + func (writer *RecordWriterPPRINT) writeHeterogenousListBarred( records []*mlrval.Mlrmap, maxWidths map[string]int, @@ -235,35 +251,65 @@ func (writer *RecordWriterPPRINT) writeHeterogenousListBarred( outputIsStdout bool, ) { + bc := func() barredChars { + ofs := writer.writerOptions.OFS + if writer.writerOptions.BarredUseUnicode { + return barredChars{ + horizontalStart: "├─", + horizontalMiddle: "─┼─", + horizontalEnd: "─┤", + horizontalBar: "─", + verticalStart: "│" + ofs, + verticalMiddle: ofs + "│" + ofs, + verticalEnd: ofs + "│", + firstRowHorizontalStart: "┌─", + firstRowHorizontalMiddle: "─┬─", + firstRowHorizontalEnd: "─┐", + lastRowHorizontalStart: "└─", + lastRowHorizontalMiddle: "─┴─", + lastRowHorizontalEnd: "─┘", + } + } else { + return barredChars{ + horizontalStart: "+-", + horizontalMiddle: "-+-", + horizontalEnd: "-+", + horizontalBar: "-", + verticalStart: "|" + ofs, + verticalMiddle: ofs + "|" + ofs, + verticalEnd: ofs + "|", + firstRowHorizontalStart: "+-", + firstRowHorizontalMiddle: "-+-", + firstRowHorizontalEnd: "-+", + lastRowHorizontalStart: "+-", + lastRowHorizontalMiddle: "-+-", + lastRowHorizontalEnd: "-+", + } + } + }() + horizontalBars := make(map[string]string) for key, width := range maxWidths { - horizontalBars[key] = strings.Repeat("-", width) + horizontalBars[key] = strings.Repeat(bc.horizontalBar, width) } - ofs := writer.writerOptions.OFS - horizontalStart := "+-" - horizontalMiddle := "-+-" - horizontalEnd := "-+" - verticalStart := "|" + ofs - verticalMiddle := ofs + "|" + ofs - verticalEnd := ofs + "|" onFirst := true for i, outrec := range records { // Print header line if onFirst && !writer.writerOptions.HeaderlessOutput { - bufferedOutputStream.WriteString(horizontalStart) + bufferedOutputStream.WriteString(bc.firstRowHorizontalStart) for pe := outrec.Head; pe != nil; pe = pe.Next { bufferedOutputStream.WriteString(horizontalBars[pe.Key]) if pe.Next != nil { - bufferedOutputStream.WriteString(horizontalMiddle) + bufferedOutputStream.WriteString(bc.firstRowHorizontalMiddle) } else { - bufferedOutputStream.WriteString(horizontalEnd) + bufferedOutputStream.WriteString(bc.firstRowHorizontalEnd) bufferedOutputStream.WriteString(writer.writerOptions.ORS) } } - bufferedOutputStream.WriteString(verticalStart) + bufferedOutputStream.WriteString(bc.verticalStart) for pe := outrec.Head; pe != nil; pe = pe.Next { if !writer.writerOptions.RightAlignedPPRINTOutput { // left-align bufferedOutputStream.WriteString(colorizer.MaybeColorizeKey(pe.Key, outputIsStdout)) @@ -273,20 +319,20 @@ func (writer *RecordWriterPPRINT) writeHeterogenousListBarred( bufferedOutputStream.WriteString(colorizer.MaybeColorizeKey(pe.Key, outputIsStdout)) } if pe.Next != nil { - bufferedOutputStream.WriteString(verticalMiddle) + bufferedOutputStream.WriteString(bc.verticalMiddle) } else { - bufferedOutputStream.WriteString(verticalEnd) + bufferedOutputStream.WriteString(bc.verticalEnd) bufferedOutputStream.WriteString(writer.writerOptions.ORS) } } - bufferedOutputStream.WriteString(horizontalStart) + bufferedOutputStream.WriteString(bc.horizontalStart) for pe := outrec.Head; pe != nil; pe = pe.Next { bufferedOutputStream.WriteString(horizontalBars[pe.Key]) if pe.Next != nil { - bufferedOutputStream.WriteString(horizontalMiddle) + bufferedOutputStream.WriteString(bc.horizontalMiddle) } else { - bufferedOutputStream.WriteString(horizontalEnd) + bufferedOutputStream.WriteString(bc.horizontalEnd) bufferedOutputStream.WriteString(writer.writerOptions.ORS) } } @@ -294,7 +340,7 @@ func (writer *RecordWriterPPRINT) writeHeterogenousListBarred( onFirst = false // Print data lines - bufferedOutputStream.WriteString(verticalStart) + bufferedOutputStream.WriteString(bc.verticalStart) for pe := outrec.Head; pe != nil; pe = pe.Next { s := pe.Value.String() if !writer.writerOptions.RightAlignedPPRINTOutput { // left-align @@ -305,21 +351,22 @@ func (writer *RecordWriterPPRINT) writeHeterogenousListBarred( bufferedOutputStream.WriteString(colorizer.MaybeColorizeValue(s, outputIsStdout)) } if pe.Next != nil { - bufferedOutputStream.WriteString(fmt.Sprint(verticalMiddle)) + bufferedOutputStream.WriteString(fmt.Sprint(bc.verticalMiddle)) } else { - bufferedOutputStream.WriteString(verticalEnd) + bufferedOutputStream.WriteString(bc.verticalEnd) bufferedOutputStream.WriteString(writer.writerOptions.ORS) } } + // Print last line if i == len(records)-1 { - bufferedOutputStream.WriteString(horizontalStart) + bufferedOutputStream.WriteString(bc.lastRowHorizontalStart) for pe := outrec.Head; pe != nil; pe = pe.Next { bufferedOutputStream.WriteString(horizontalBars[pe.Key]) if pe.Next != nil { - bufferedOutputStream.WriteString(horizontalMiddle) + bufferedOutputStream.WriteString(bc.lastRowHorizontalMiddle) } else { - bufferedOutputStream.WriteString(horizontalEnd) + bufferedOutputStream.WriteString(bc.lastRowHorizontalEnd) bufferedOutputStream.WriteString(writer.writerOptions.ORS) } }