Commit c915d1bd authored by liming6's avatar liming6
Browse files

fix 处理条形图显示逻辑

parent ed4a196f
......@@ -21,7 +21,7 @@ func main() {
log.Fatalf("error init data backend: %v", err)
}
model := tui.NewModelMain(w, h)
if _, err := tea.NewProgram(&model, tea.WithAltScreen()).Run(); err != nil {
if _, err := tea.NewProgram(&model).Run(); err != nil {
log.Fatalf("error create program; %v", err)
}
backend.Shutdown()
......
......@@ -65,16 +65,16 @@ func NewModelSysLoad(width int) *ModelSysLoad {
}
return 0
})
result.colors = gamut.Blends(lipgloss.Color("#ff0000"), lipgloss.Color("#00ff00ff"), SysLoadHeight)
subLine := width - StaticWidth - 1
result.SysMem = NewTimeChart(SysLoadWidth, SysLoadHeight, 0, 100, map[string]lipgloss.Color{"default": lipgloss.Color("#20ff2cff")})
result.SysCPU = NewTimeChart(SysLoadWidth, SysLoadHeight, 0, 100, map[string]lipgloss.Color{"default": lipgloss.Color("#ff3030ff")})
result.DCU = NewTimeChart(subLine, SysLoadHeight, 0, 100, map[string]lipgloss.Color{"default": lipgloss.Color("#27ffdbff")})
result.DCUMem = NewTimeChart(subLine, SysLoadHeight, 0, 100, map[string]lipgloss.Color{"default": lipgloss.Color("#20b1ffff")})
result.SysMem = NewTimeChart(SysLoadWidth, SysLoadHeight, 0, 100, result.colors)
result.SysCPU = NewTimeChart(SysLoadWidth, SysLoadHeight, 0, 100, result.colors)
result.DCU = NewTimeChart(subLine, SysLoadHeight, 0, 100, result.colors)
result.DCUMem = NewTimeChart(subLine, SysLoadHeight, 0, 100, result.colors)
result.topLine = myBorder.MiddleLeft + genXAxis(SysLoadWidth) + myBorder.Middle + genXAxis(subLine) + myBorder.MiddleRight
result.bottomLine = "╞" + strings.Repeat(myBorder.Bottom, SysLoadWidth) + "╧" + strings.Repeat(myBorder.Bottom, subLine) + "╡"
result.style = lipgloss.NewStyle()
result.colors = gamut.Blends(lipgloss.Color("#ff0000"), lipgloss.Color("#00ff00ff"), SysLoadHeight)
return &result
}
......@@ -212,22 +212,22 @@ func (m *ModelSysLoad) updateInfo(t *ModelMsg) {
wg.Add(4)
go func() {
defer wg.Done()
m1, _ := m.SysMem.Update(MyTimeChartMsg{Points: map[string][]tchart.TimePoint{"default": {{Time: t.t, Value: s.MemUsedPercent}}}})
m1, _ := m.SysMem.Update(MyTimeChartMsg{[]tchart.TimePoint{{Time: t.t, Value: s.MemUsedPercent}}})
m.SysMem = m1.(*MyTimeChart)
}()
go func() {
defer wg.Done()
m2, _ := m.SysCPU.Update(MyTimeChartMsg{Points: map[string][]tchart.TimePoint{"default": {{Time: t.t, Value: s.CPUPercent}}}})
m2, _ := m.SysCPU.Update(MyTimeChartMsg{[]tchart.TimePoint{{Time: t.t, Value: s.CPUPercent}}})
m.SysCPU = m2.(*MyTimeChart)
}()
go func() {
defer wg.Done()
m3, _ := m.DCU.Update(MyTimeChartMsg{Points: map[string][]tchart.TimePoint{"default": {{Time: t.t, Value: float64(s.DCUUsageAvg)}}}})
m3, _ := m.DCU.Update(MyTimeChartMsg{[]tchart.TimePoint{{Time: t.t, Value: float64(s.DCUUsageAvg)}}})
m.DCU = m3.(*MyTimeChart)
}()
go func() {
defer wg.Done()
m4, _ := m.DCUMem.Update(MyTimeChartMsg{Points: map[string][]tchart.TimePoint{"default": {{Time: t.t, Value: float64(s.DCUMemUsageAvg)}}}})
m4, _ := m.DCUMem.Update(MyTimeChartMsg{[]tchart.TimePoint{{Time: t.t, Value: float64(s.DCUMemUsageAvg)}}})
m.DCUMem = m4.(*MyTimeChart)
}()
// 存放数据
......
package tui
import (
"image/color"
"sort"
"strconv"
"strings"
......@@ -8,11 +9,13 @@ import (
"time"
"get-container/cmd/hytop/tchart"
"get-container/utils"
"github.com/NimbleMarkets/ntcharts/canvas/runes"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
zone "github.com/lrstanley/bubblezone"
"github.com/lucasb-eyer/go-colorful"
)
const (
......@@ -56,23 +59,22 @@ func genXAxis(l int) string {
// MyTimeChartMsg 时间流表消息,用于插入数据
type MyTimeChartMsg struct {
Points map[string][]tchart.TimePoint
Points []tchart.TimePoint
}
// MyTimeChart 特化的时间流表,时间区域就是宽度的2倍,单位是秒
type MyTimeChart struct {
chart *tchart.Model // 原始图表
zM *zone.Manager // 区域管理
dataSet map[string][]tchart.TimePoint // 数据点
points []tchart.TimePoint // 数据点
width, height int // 图表的高度和宽度
max, min float64 // y轴的最值
dataStyle map[string]lipgloss.Style // 记录每个数据集的样式
lockDataSet sync.RWMutex // 保护dataSet的并发读写
lockChart sync.RWMutex // 保护chart的数据集的并发读写
lockPoints sync.RWMutex // 保护dataSet的并发读写
color []color.Color
}
// New 新建图表,其中dataSet的Key为数据集名称,value为数据集的颜色
func NewTimeChart(width, height int, vmin, vmax float64, dataSet map[string]lipgloss.Color) *MyTimeChart {
func NewTimeChart(width, height int, vmin, vmax float64, color []color.Color) *MyTimeChart {
result := MyTimeChart{}
result.max = vmax
result.min = vmin
......@@ -80,70 +82,30 @@ func NewTimeChart(width, height int, vmin, vmax float64, dataSet map[string]lipg
result.height = height
zoneManager := zone.New()
result.zM = zoneManager
result.dataSet = make(map[string][]tchart.TimePoint)
result.dataStyle = make(map[string]lipgloss.Style)
result.lockChart = sync.RWMutex{}
result.lockDataSet = sync.RWMutex{}
result.lockDataSet.Lock()
for k, v := range dataSet {
result.dataSet[k] = make([]tchart.TimePoint, (result.width*2)+1)
result.dataStyle[k] = lipgloss.NewStyle().Foreground(v)
}
initPoints := make([]tchart.TimePoint, (result.width*2)+1)
result.lockPoints = sync.RWMutex{}
result.lockPoints.Lock()
result.points = make([]tchart.TimePoint, (result.width*2)+1)
// 准备数据,数据间隔为1秒
now := time.Now()
for i := result.width * 2; i >= 0; i-- {
initPoints[i] = tchart.TimePoint{Time: now.Add(time.Duration(-i) * time.Second), Value: vmin}
result.points[i] = tchart.TimePoint{Time: now.Add(time.Duration(-i) * time.Second), Value: vmin}
}
for k := range dataSet {
copy(result.dataSet[k], initPoints)
}
result.lockDataSet.Unlock()
result.lockPoints.Unlock()
s := tchart.New(width, height+1,
tchart.WithLineStyle(runes.ThinLineStyle),
tchart.WithZoneManager(zoneManager),
tchart.WithYRange(vmin, vmax),
tchart.WithXYSteps(0, 0),
tchart.WithTimeSeries(result.points),
)
wg := sync.WaitGroup{}
wg.Add(len(dataSet))
for k := range dataSet {
points := result.dataSet[k]
style := result.dataStyle[k]
go func(ps []tchart.TimePoint, st lipgloss.Style, key string) {
result.lockChart.Lock()
s.SetDataSet(key, ps)
s.SetDataSetStyle(key, st)
result.lockChart.Unlock()
wg.Done()
}(points, style, k)
}
wg.Wait()
result.chart = &s
result.color = color
return &result
}
func (m *MyTimeChart) PutPoint(points map[string][]tchart.TimePoint) {
// 更新chart
s := tchart.New(m.width, m.height+1,
tchart.WithLineStyle(runes.ThinLineStyle),
tchart.WithZoneManager(m.zM),
tchart.WithYRange(m.min, m.max),
tchart.WithXYSteps(0, 0),
)
m.chart = &s
wg := sync.WaitGroup{}
wg.Add(len(m.dataSet))
keys, index := make([]string, len(m.dataSet)), 0
for k := range m.dataSet {
keys[index] = k
index++
}
for _, k := range keys {
newPoints := points[k]
oldPoints := m.dataSet[k]
go func(ops, nps []tchart.TimePoint, ds map[string][]tchart.TimePoint, key string) {
ops = append(ops, nps...)
func (m *MyTimeChart) PutPoint(points []tchart.TimePoint) {
ops := append(m.points, points...)
// 排序
sort.Slice(ops, func(i, j int) bool {
return ops[i].Time.Before(ops[j].Time)
})
......@@ -155,18 +117,18 @@ func (m *MyTimeChart) PutPoint(points map[string][]tchart.TimePoint) {
break
}
}
nps = append(make([]tchart.TimePoint, 0), ops[targetIndex:]...)
m.lockDataSet.Lock()
ds[key] = nps
m.lockDataSet.Unlock()
m.lockChart.Lock()
s.SetDataSet(key, nps)
s.SetDataSetStyle(key, m.dataStyle[key])
m.lockChart.Unlock()
wg.Done()
}(oldPoints, newPoints, m.dataSet, k)
}
wg.Wait()
nps := append(make([]tchart.TimePoint, 0), ops[targetIndex:]...)
m.points = nps
s := tchart.New(m.width, m.height+1,
tchart.WithLineStyle(runes.ThinLineStyle),
tchart.WithZoneManager(m.zM),
tchart.WithYRange(m.min, m.max),
tchart.WithXYSteps(0, 0),
tchart.WithTimeSeries(m.points),
)
// 插入数据
m.chart = nil
m.chart = &s
m.chart.DrawXYAxisAndLabel()
m.chart.DrawBrailleAll()
}
......@@ -187,9 +149,85 @@ func (m *MyTimeChart) Update(inputMsg tea.Msg) (tea.Model, tea.Cmd) {
}
func (m *MyTimeChart) View() string {
rl := m.lockChart.RLocker()
rl.Lock()
str := m.zM.Scan(m.chart.View())
rl.Unlock()
return str[m.width+1:]
sb := strings.Builder{}
sb.WriteString(str[m.width+1:])
str = sb.String()
// return str
lines := strings.Split(strings.Trim(str, "\n"), "\n")
runes := make([][]rune, len(lines))
for k, v := range lines {
runes[k] = []rune(v)
}
width := lipgloss.Width(str)
height := lipgloss.Height(str)
for col := range width {
firstLine := -1
var charStat utils.CharType = utils.CharEmpty
for line := range height {
c := runes[line][col]
charType := utils.GetCharType(c)
if charType != utils.CharEmpty && firstLine == -1 {
firstLine = line
}
if firstLine == -1 {
continue
}
if firstLine == line {
// 遇到了一列的第一个非空字符
if t, have := utils.MM[c]; have {
runes[line][col] = t
}
charStat = utils.CharTypeOr(charStat, utils.GetCharType(runes[line][col]))
} else {
// 第一个非空字符下面的字符
switch charType {
case utils.CharEmpty:
switch charStat {
case utils.CharLeft:
runes[line][col] = utils.LeftFullMW
case utils.CharRight:
runes[line][col] = utils.RightFullMW
case utils.CharFull:
runes[line][col] = utils.FullMW
}
case utils.CharLeft:
switch utils.CharTypeOr(charStat, utils.CharLeft) {
case utils.CharLeft:
runes[line][col] = utils.LeftFullMW
case utils.CharRight:
runes[line][col] = utils.RightFullMW
case utils.CharFull:
runes[line][col] = utils.FullMW
}
charStat = utils.CharTypeOr(charStat, utils.CharLeft)
case utils.CharRight:
switch utils.CharTypeOr(charStat, utils.CharRight) {
case utils.CharLeft:
runes[line][col] = utils.LeftFullMW
case utils.CharRight:
runes[line][col] = utils.RightFullMW
case utils.CharFull:
runes[line][col] = utils.FullMW
}
charStat = utils.CharTypeOr(charStat, utils.CharRight)
case utils.CharFull:
charStat = utils.CharFull
}
}
}
}
resultLines := make([]string, height)
for k, v := range runes {
resultLines[k] = string(v)
}
if len(m.color) == height {
for k, v := range resultLines {
c, _ := colorful.MakeColor(m.color[k])
resultLines[k] = lipgloss.NewStyle().Foreground(lipgloss.Color(c.Hex())).Render(v)
}
}
return strings.Join(resultLines, "\n")
}
......@@ -3,7 +3,6 @@ package tui
import (
"fmt"
"get-container/cmd/hytop/backend"
"get-container/cmd/hytop/tchart"
"testing"
"time"
......@@ -50,27 +49,6 @@ func TestModel(t *testing.T) {
t.Log(str)
}
func TestMyTimeChart(t *testing.T) {
chart := NewTimeChart(100, 5, 0.0, 100.0, map[string]lipgloss.Color{"default": lipgloss.Color("#ff2222ff"), "other": lipgloss.Color("#0037ffff")})
chart.Init()
s := chart.View()
t.Logf("\n%s", s)
time.Sleep(time.Second)
now := time.Now()
points := make(map[string][]tchart.TimePoint)
points["default"] = []tchart.TimePoint{{Time: now, Value: 94.0}}
points["other"] = []tchart.TimePoint{{Time: now, Value: 94.0}}
chart.Update(MyTimeChartMsg{Points: points})
time.Sleep(time.Second)
now = time.Now()
points = make(map[string][]tchart.TimePoint)
points["default"] = []tchart.TimePoint{{Time: now, Value: 0.0}}
points["other"] = []tchart.TimePoint{{Time: now, Value: 0.0}}
chart.Update(MyTimeChartMsg{Points: points})
t.Logf("\n%s", chart.View())
t.Logf("ok")
}
func TestBinaryHeap(t *testing.T) {
err := backend.Init()
if err != nil {
......
⠀|⠁|⠂|⠃|⠄|⠅|⠆|⠇|⠈|⠉|⠊|⠋|⠌|⠍|⠎|⠏
⠐|⠑|⠒|⠓|⠔|⠕|⠖|⠗|⠘|⠙|⠚|⠛|⠜|⠝|⠞|⠟
⠠|⠡|⠢|⠣|⠤|⠥|⠦|⠧|⠨|⠩|⠪|⠫|⠬|⠭|⠮|⠯
⠰|⠱|⠲|⠳|⠴|⠵|⠶|⠷|⠸|⠹|⠺|⠻|⠼|⠽|⠾|⠿
⡀|⡁|⡂|⡃|⡄|⡅|⡆|⡇|⡈|⡉|⡊|⡋|⡌|⡍|⡎|⡏
⡐|⡑|⡒|⡓|⡔|⡕|⡖|⡗|⡘|⡙|⡚|⡛|⡜|⡝|⡞|⡟
⡠|⡡|⡢|⡣|⡤|⡥|⡦|⡧|⡨|⡩|⡪|⡫|⡬|⡭|⡮|⡯
⡰|⡱|⡲|⡳|⡴|⡵|⡶|⡷|⡸|⡹|⡺|⡻|⡼|⡽|⡾|⡿
⢀|⢁|⢂|⢃|⢄|⢅|⢆|⢇|⢈|⢉|⢊|⢋|⢌|⢍|⢎|⢏
⢐|⢑|⢒|⢓|⢔|⢕|⢖|⢗|⢘|⢙|⢚|⢛|⢜|⢝|⢞|⢟
⢠|⢡|⢢|⢣|⢤|⢥|⢦|⢧|⢨|⢩|⢪|⢫|⢬|⢭|⢮|⢯
⢰|⢱|⢲|⢳|⢴|⢵|⢶|⢷|⢸|⢹|⢺|⢻|⢼|⢽|⢾|⢿
⣀|⣁|⣂|⣃|⣄|⣅|⣆|⣇|⣈|⣉|⣊|⣋|⣌|⣍|⣎|⣏
⣐|⣑|⣒|⣓|⣔|⣕|⣖|⣗|⣘|⣙|⣚|⣛|⣜|⣝|⣞|⣟
⣠|⣡|⣢|⣣|⣤|⣥|⣦|⣧|⣨|⣩|⣪|⣫|⣬|⣭|⣮|⣯
⣰|⣱|⣲|⣳|⣴|⣵|⣶|⣷|⣸|⣹|⣺|⣻|⣼|⣽|⣾|⣿
⠁⠂⠄⡀
package utils
import (
"slices"
"strings"
)
type CharType byte
const (
MW = `
⠀⠀|⠁⡇|⠂⡆|⠃⡇|⠄⡄|⠅⡇|⠆⡆|⠇⡇|⠈⢸|⠉⣿|⠊⣾|⠋⣿|⠌⣼|⠍⣿|⠎⣾|⠏⣿
⠐⢰|⠑⣷|⠒⣶|⠓⣷|⠔⣴|⠕⣷|⠖⣶|⠗⣷|⠘⢸|⠙⣿|⠚⣾|⠛⣿|⠜⣼|⠝⣿|⠞⣾|⠟⣿
⠠⢠|⠡⣧|⠢⣦|⠣⣧|⠤⣤|⠥⣧|⠦⣦|⠧⣧|⠨⢸|⠩⣿|⠪⣾|⠫⣿|⠬⣼|⠭⣿|⠮⣾|⠯⣿
⠰⢰|⠱⣷|⠲⣶|⠳⣷|⠴⣴|⠵⣷|⠶⣶|⠷⣷|⠸⢸|⠹⣿|⠺⣾|⠻⣿|⠼⣼|⠽⣿|⠾⣾|⠿⣿
⡀⡀|⡁⡇|⡂⡆|⡃⡇|⡄⡄|⡅⡇|⡆⡆|⡇⡇|⡈⣸|⡉⣿|⡊⣾|⡋⣿|⡌⣾|⡍⣿|⡎⣾|⡏⣿
⡐⣰|⡑⣷|⡒⣶|⡓⣷|⡔⣴|⡕⣷|⡖⣶|⡗⣷|⡘⣸|⡙⣿|⡚⣾|⡛⣿|⡜⣼|⡝⣿|⡞⣾|⡟⣿
⡠⣠|⡡⣧|⡢⣦|⡣⣧|⡤⣤|⡥⣧|⡦⣦|⡧⣧|⡨⣸|⡩⣿|⡪⣾|⡫⣿|⡬⣼|⡭⣿|⡮⣾|⡯⣿
⡰⣰|⡱⣷|⡲⣶|⡳⣷|⡴⣴|⡵⣷|⡶⣶|⡷⣷|⡸⣸|⡹⣿|⡺⣾|⡻⣿|⡼⣼|⡽⣿|⡾⣾|⡿⣿
⢀⢀|⢁⣇|⢂⣆|⢃⣇|⢄⣄|⢅⣇|⢆⣆|⢇⣇|⢈⢸|⢉⣿|⢊⣾|⢋⣿|⢌⣼|⢍⣿|⢎⣾|⢏⣿
⢐⢰|⢑⣷|⢒⣶|⢓⣷|⢔⣴|⢕⣷|⢖⣶|⢗⣷|⢘⢸|⢙⣿|⢚⣾|⢛⣿|⢜⣼|⢝⣿|⢞⣾|⢟⣿
⢠⢠|⢡⣧|⢢⣦|⢣⣧|⢤⣤|⢥⣧|⢦⣦|⢧⣧|⢨⢸|⢩⣿|⢪⣾|⢫⣿|⢬⣼|⢭⣿|⢮⣾|⢯⣿
⢰⢰|⢱⣷|⢲⣶|⢳⣷|⢴⣴|⢵⣷|⢶⣶|⢷⣷|⢸⢸|⢹⣿|⢺⣾|⢻⣿|⢼⣼|⢽⣿|⢾⣾|⢿⣿
⣀⣀|⣁⣇|⣂⣆|⣃⣇|⣄⣄|⣅⣇|⣆⣆|⣇⣇|⣈⣸|⣉⣿|⣊⣾|⣋⣿|⣌⣼|⣍⣿|⣎⣾|⣏⣿
⣐⣰|⣑⣷|⣒⣶|⣓⣷|⣔⣴|⣕⣷|⣖⣶|⣗⣷|⣘⣸|⣙⣿|⣚⣾|⣛⣿|⣜⣼|⣝⣿|⣞⣾|⣟⣿
⣠⣠|⣡⣧|⣢⣦|⣣⣧|⣤⣤|⣥⣧|⣦⣦|⣧⣧|⣨⣸|⣩⣿|⣪⣾|⣫⣿|⣬⣼|⣭⣿|⣮⣾|⣯⣿
⣰⣰|⣱⣷|⣲⣶|⣳⣷|⣴⣴|⣵⣷|⣶⣶|⣷⣷|⣸⣸|⣹⣿|⣺⣾|⣻⣿|⣼⣼|⣽⣿|⣾⣾|⣿⣿
`
SpaceMW = rune('⠀')
FullMW = rune('⣿')
LeftFullMW = rune('⡇')
RightFullMW = rune('⢸')
OneThreeMW = rune('⣸')
CharLeft CharType = 1 << 2
CharRight CharType = 1 << 1
CharEmpty CharType = 0
CharFull CharType = CharLeft + CharRight
)
var (
MM = Full()
LeftOnlyMW = []rune("⠁⠂⠄⡀⠃⡄⠆⠅⡁⡂⡆⠇⡃⡅⡇")
RightOnlyMW = []rune("⠈⠐⠠⢀⠘⠰⠨⢈⢐⢠⢘⢨⠸⢰⢸")
)
/*
├─────────────120s├──────────────────────────60s├───────────30s├──────────────┼──────────────────────360s├─────────────────────────300s├─────────────────────────240s├─────────────────────────180s├─────────────────────────120s├──────────────────────────60s├───────────30s├──────────────┤
│ │ ⡏⠉⡇⣿⢸⢹ │
│ │ ⡇ ⢣⠃⠇⠈⡆ │
│ │ ⡇ ⠸ ⡇ │
│ │ ⡇ ⢣ │
│ MEM: 93.0GiB (6.2%)⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⠤⠤⠤⠤⠤⠤⠤⠤⠄│ AVG DCU UTL: 0.0%⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⡇ ⢸⣀⣀⣀⣀⣀⡀│
*/
func Full() map[rune]rune {
result := make(map[rune]rune)
str := strings.ReplaceAll(strings.ReplaceAll(strings.Trim(MW, "\n"), "|", ""), "\n", "")
runes := []rune(str)
l := len(runes) / 2
for i := range l {
k := runes[2*i]
v := runes[2*i+1]
if k != v {
result[k] = v
}
}
return result
}
func GetCharType(r rune) CharType {
if r == ' ' || r == SpaceMW {
return CharEmpty
}
if slices.Contains(LeftOnlyMW, r) {
return CharLeft
}
if slices.Contains(RightOnlyMW, r) {
return CharRight
}
return CharFull
}
func CharTypeOr(a, b CharType) CharType {
return CharType(a | b)
}
package utils
import (
"fmt"
"strings"
"sync/atomic"
"testing"
)
......@@ -76,3 +78,37 @@ func TestPCIBusId(t *testing.T) {
i := atomic.Int32{}
t.Log(i.Load())
}
func TestTimesort(t *testing.T) {
fmt.Println("--- 打印所有 256 个 8 点盲文(Unicode 字符)---")
fmt.Println(" (如果您的字体支持,将显示从 U+2800 到 U+28FF 的符号)")
fmt.Println(strings.Repeat("-", 60))
// 8点盲文的 Unicode 范围是 U+2800 到 U+28FF
const startCodePoint = 0x2800
const endCodePoint = 0x28FF
const charsPerRow = 16 // 每行打印 16 个字符,共 16 行
// 循环遍历并打印所有 256 个字符
for i := startCodePoint; i <= endCodePoint; i++ {
// 打印 Unicode 符号本身
fmt.Printf("%c", rune(i))
// 每 16 个字符换一行
if (i-startCodePoint+1)%charsPerRow == 0 {
fmt.Print("\n")
} else {
fmt.Print("|") // 字符之间用空格分隔
}
}
fmt.Println(strings.Repeat("-", 60))
fmt.Println("所有 256 个组合打印完成 (从 U+2800 到 U+28FF)。")
}
func TestChartype(t *testing.T) {
r := GetCharType(LeftFullMW)
t.Log(r)
t.Log(CharTypeOr(GetCharType(' '), GetCharType(' ')))
t.Log(GetCharType('⢠'))
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment