mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-09-15 21:00:27 +00:00
150 lines
3.1 KiB
Go
150 lines
3.1 KiB
Go
package main
|
|
|
|
import (
|
|
"os"
|
|
"strings"
|
|
|
|
"github.com/sagernet/sing/common"
|
|
|
|
"github.com/mattn/go-runewidth"
|
|
"golang.org/x/term"
|
|
)
|
|
|
|
var (
|
|
stdoutIsTerminal = term.IsTerminal(int(os.Stdout.Fd()))
|
|
stderrIsTerminal = term.IsTerminal(int(os.Stderr.Fd()))
|
|
)
|
|
|
|
func writeStderrLine(message string) {
|
|
if !stderrIsTerminal {
|
|
return
|
|
}
|
|
os.Stderr.WriteString(message + "\n")
|
|
}
|
|
|
|
func writeProgress(message string) {
|
|
if !stderrIsTerminal {
|
|
return
|
|
}
|
|
os.Stderr.WriteString("\r" + message)
|
|
}
|
|
|
|
func stripColors(message string) string {
|
|
if !strings.Contains(message, "\x1b[") {
|
|
return message
|
|
}
|
|
var builder strings.Builder
|
|
start := 0
|
|
for index := 0; index < len(message); {
|
|
if message[index] != '\x1b' || index+1 >= len(message) || message[index+1] != '[' {
|
|
index++
|
|
continue
|
|
}
|
|
end := index + 2
|
|
for end < len(message) && message[end] != 'm' {
|
|
end++
|
|
}
|
|
if end >= len(message) {
|
|
break
|
|
}
|
|
builder.WriteString(message[start:index])
|
|
index = end + 1
|
|
start = index
|
|
}
|
|
builder.WriteString(message[start:])
|
|
return builder.String()
|
|
}
|
|
|
|
type tableWriter struct {
|
|
header []string
|
|
emptyMessage string
|
|
rows [][]string
|
|
}
|
|
|
|
func (t *tableWriter) addRow(cells ...string) {
|
|
t.rows = append(t.rows, common.Map(cells, func(it string) string {
|
|
if it == "" {
|
|
return "-"
|
|
}
|
|
return it
|
|
}))
|
|
}
|
|
|
|
func (t *tableWriter) flush() {
|
|
if len(t.rows) == 0 {
|
|
writeStderrLine(t.emptyMessage)
|
|
return
|
|
}
|
|
if !stdoutIsTerminal {
|
|
var output strings.Builder
|
|
for _, row := range t.rows {
|
|
output.WriteString(strings.Join(row, "\t"))
|
|
output.WriteString("\n")
|
|
}
|
|
os.Stdout.WriteString(output.String())
|
|
return
|
|
}
|
|
widths := common.Map(t.header, func(it string) int {
|
|
return runewidth.StringWidth(it)
|
|
})
|
|
for _, row := range t.rows {
|
|
for index, cell := range row {
|
|
widths[index] = max(widths[index], runewidth.StringWidth(cell))
|
|
}
|
|
}
|
|
renderRow := func(cells []string) string {
|
|
var builder strings.Builder
|
|
for index, cell := range cells {
|
|
if index > 0 {
|
|
builder.WriteString(" ")
|
|
}
|
|
builder.WriteString(cell)
|
|
if index < len(cells)-1 {
|
|
builder.WriteString(strings.Repeat(" ", widths[index]-runewidth.StringWidth(cell)))
|
|
}
|
|
}
|
|
return builder.String()
|
|
}
|
|
writeStderrLine(renderRow(t.header))
|
|
var output strings.Builder
|
|
for _, row := range t.rows {
|
|
output.WriteString(renderRow(row))
|
|
output.WriteString("\n")
|
|
}
|
|
os.Stdout.WriteString(output.String())
|
|
}
|
|
|
|
type blockLine struct {
|
|
label string
|
|
value string
|
|
}
|
|
|
|
type blockWriter struct {
|
|
lines []blockLine
|
|
}
|
|
|
|
func (b *blockWriter) addLine(label string, value string) {
|
|
if value == "" {
|
|
value = "-"
|
|
}
|
|
b.lines = append(b.lines, blockLine{label: label, value: value})
|
|
}
|
|
|
|
func (b *blockWriter) flush() {
|
|
if len(b.lines) == 0 {
|
|
return
|
|
}
|
|
labelWidth := len(common.MaxBy(b.lines, func(it blockLine) int {
|
|
return len(it.label)
|
|
}).label) + 3
|
|
var output strings.Builder
|
|
for _, line := range b.lines {
|
|
output.WriteString(line.label)
|
|
output.WriteString(":")
|
|
output.WriteString(strings.Repeat(" ", labelWidth-len(line.label)-1))
|
|
output.WriteString(line.value)
|
|
output.WriteString("\n")
|
|
}
|
|
os.Stdout.WriteString(output.String())
|
|
}
|