diff --git a/table.go b/table.go index bc5567f..e453ea1 100644 --- a/table.go +++ b/table.go @@ -23,11 +23,12 @@ const ( ) const ( - CENTER = "+" - ROW = "-" - COLUMN = "|" - SPACE = " " - NEWLINE = "\n" + CENTER = "+" + ROW = "-" + COLUMN = "|" + SPACE = " " + NEWLINE = "\n" + DEAULT_MERGED_LINE_SEPERATOR = "*&*" ) const ( @@ -444,6 +445,32 @@ func (t *Table) Append(row []string) { // Append broken words line = append(line, out) } + + // If autMerge is true and cells are set, we will merge current line into pre line. + // This will reduce the height of the table. Because we only print one line with merged cells. + if t.autoMergeCells && len(t.columnsToAutoMergeCells) > 0 && n > 0 { + pre := t.lines[n-1] + equal := true + for col := range t.columnsToAutoMergeCells { + if !reflect.DeepEqual(pre[col], line[col]) { + equal = false + } + } + if equal { + max := t.rs[n-1] + for i := range pre { + if t.columnsToAutoMergeCells[i] { + continue + } + pre[i] = append(pre[i], DEAULT_MERGED_LINE_SEPERATOR) + pre[i] = append(pre[i], line[i]...) + if len(pre[i]) > max { + t.rs[n-1] = len(pre[i]) + } + } + return + } + } t.lines = append(t.lines, line) } @@ -994,12 +1021,20 @@ func (t *Table) printRowMergeCells(writer io.Writer, columns [][]string, rowIdx // Check if border is set fmt.Fprint(writer, ConditionString((!t.borders.Left && y == 0), SPACE, t.syms[symNS])) - fmt.Fprintf(writer, SPACE) - str := columns[y][x] + isMergedLine := false + if str == DEAULT_MERGED_LINE_SEPERATOR { + isMergedLine = true + v := t.cs[y] + str = fmt.Sprintf("%s%s%s", t.pRow, strings.Repeat(string(t.pRow), v), t.pRow) + } + + if !isMergedLine { + fmt.Fprintf(writer, SPACE) + } // Embedding escape sequence with column value - if isEscSeq { + if isEscSeq && !isMergedLine { str = format(str, t.columnsParams[y]) } @@ -1042,7 +1077,10 @@ func (t *Table) printRowMergeCells(writer io.Writer, columns [][]string, rowIdx fmt.Fprintf(writer, "%s", PadRight(str, SPACE, t.cs[y])) } } - fmt.Fprintf(writer, SPACE) + + if !isMergedLine { + fmt.Fprintf(writer, SPACE) + } } // Check if border is set // Replace with space if not set diff --git a/util.go b/util.go index 6056bee..33ba243 100644 --- a/util.go +++ b/util.go @@ -17,8 +17,19 @@ import ( var ansi = regexp.MustCompile("\033\\[(?:[0-9]{1,3}(?:;[0-9]{1,3})*)?[m|K]") +var linkRe = regexp.MustCompile(`\x1b]8;;.*?\x1b\\(.*?)(\x1b]8;;\x1b\\)?`) + func DisplayWidth(str string) int { - return runewidth.StringWidth(ansi.ReplaceAllLiteralString(str, "")) + linkFreeText := CleanHyperlinksInTerminalEmulators(str) + return runewidth.StringWidth(ansi.ReplaceAllLiteralString(linkFreeText, "")) +} + +// CleanHyperlinksInTerminalEmulators +// https://github.com/Alhadis/OSC8-Adoption/ +// printf '\033]8;;http://example.com\033\\This is a link\033]8;;\033\\\n' +// -> "This is a link\n" +func CleanHyperlinksInTerminalEmulators(str string) string { + return linkRe.ReplaceAllString(str, "$1") } // ConditionString Simple Condition for string diff --git a/util_test.go b/util_test.go new file mode 100644 index 0000000..6edfd42 --- /dev/null +++ b/util_test.go @@ -0,0 +1,31 @@ +package tablewriter + +import ( + "strings" + "testing" +) + +func TestCleanHyperlinksInTerminalEmulators(t *testing.T) { + testInput := "\033]8;;http://example.com\033\\This is a link\033]8;;\033\\\n" + expectedOutput := "This is a link\n" + actualOutput := CleanHyperlinksInTerminalEmulators(testInput) + if actualOutput != expectedOutput { + t.Errorf("Expected %s, got %s", expectedOutput, actualOutput) + } + expectedOutputSize := len(expectedOutput) + actualOutputSize := len(actualOutput) + if actualOutputSize != expectedOutputSize { + t.Errorf("Expected size %d, got size %d", expectedOutputSize, actualOutputSize) + } + testInput2 := strings.Repeat(testInput, 10) + expectedOutput2 := strings.Repeat(expectedOutput, 10) + actualOutput2 := CleanHyperlinksInTerminalEmulators(testInput2) + if actualOutput2 != expectedOutput2 { + t.Errorf("Expected %s, got %s", expectedOutput2, actualOutput2) + } + expectedOutputSize2 := len(expectedOutput2) + actualOutputSize2 := len(actualOutput2) + if actualOutputSize2 != expectedOutputSize2 { + t.Errorf("Expected size %d, got size %d", expectedOutputSize2, actualOutputSize2) + } +}