Fix table formatting

This commit is contained in:
Martin
2024-05-25 00:28:34 +02:00
parent f7b54b607b
commit 5d930685a3
8 changed files with 235 additions and 249 deletions

View File

@ -1,25 +1,29 @@
package common
import (
"errors"
"log/slog"
"math"
"strconv"
"strings"
// "github.com/charmbracelet/bubbles/table"
"github.com/charmbracelet/huh"
"github.com/charmbracelet/lipgloss"
"tasksquire/components/table"
"tasksquire/taskwarrior"
)
type TableStyle struct {
Header lipgloss.Style
Cell lipgloss.Style
Selected lipgloss.Style
}
type Styles struct {
Main lipgloss.Style
Base lipgloss.Style
Form *huh.Theme
TableStyle table.Styles
TableStyle TableStyle
Active lipgloss.Style
Alternate lipgloss.Style
@ -72,13 +76,13 @@ type Styles struct {
func NewStyles(config *taskwarrior.TWConfig) *Styles {
styles := parseColors(config.GetConfig())
styles.Main = lipgloss.NewStyle()
styles.Base = lipgloss.NewStyle()
styles.TableStyle = table.Styles{
styles.TableStyle = TableStyle{
// Header: lipgloss.NewStyle().Bold(true).Padding(0, 1).BorderBottom(true),
Cell: lipgloss.NewStyle().Padding(0, 1, 0, 0),
Header: lipgloss.NewStyle().Bold(true).Padding(0, 1, 0, 0).Underline(true),
Selected: lipgloss.NewStyle().Foreground(styles.Active.GetForeground()).Background(styles.Active.GetBackground()).Bold(true).Reverse(true),
Selected: lipgloss.NewStyle().Bold(true).Reverse(true),
}
formTheme := huh.ThemeBase()
@ -104,104 +108,102 @@ func parseColors(config map[string]string) *Styles {
for key, value := range config {
if strings.HasPrefix(key, "color.") {
if value != "" {
color := strings.Split(key, ".")[1]
switch color {
case "active":
styles.Active = parseColorString(value)
case "alternate":
styles.Alternate = parseColorString(value)
case "blocked":
styles.Blocked = parseColorString(value)
case "blocking":
styles.Blocking = parseColorString(value)
case "burndown.done":
styles.BurndownDone = parseColorString(value)
case "burndown.pending":
styles.BurndownPending = parseColorString(value)
case "burndown.started":
styles.BurndownStarted = parseColorString(value)
case "calendar.due":
styles.CalendarDue = parseColorString(value)
case "calendar.due.today":
styles.CalendarDueToday = parseColorString(value)
case "calendar.holiday":
styles.CalendarHoliday = parseColorString(value)
case "calendar.overdue":
styles.CalendarOverdue = parseColorString(value)
case "calendar.scheduled":
styles.CalendarScheduled = parseColorString(value)
case "calendar.today":
styles.CalendarToday = parseColorString(value)
case "calendar.weekend":
styles.CalendarWeekend = parseColorString(value)
case "calendar.weeknumber":
styles.CalendarWeeknumber = parseColorString(value)
case "completed":
styles.Completed = parseColorString(value)
case "debug":
styles.Debug = parseColorString(value)
case "deleted":
styles.Deleted = parseColorString(value)
case "due":
styles.Due = parseColorString(value)
case "due.today":
styles.DueToday = parseColorString(value)
case "error":
styles.Error = parseColorString(value)
case "footnote":
styles.Footnote = parseColorString(value)
case "header":
styles.Header = parseColorString(value)
case "history.add":
styles.HistoryAdd = parseColorString(value)
case "history.delete":
styles.HistoryDelete = parseColorString(value)
case "history.done":
styles.HistoryDone = parseColorString(value)
case "label":
styles.Label = parseColorString(value)
case "label.sort":
styles.LabelSort = parseColorString(value)
case "overdue":
styles.Overdue = parseColorString(value)
case "project.none":
styles.ProjectNone = parseColorString(value)
case "recurring":
styles.Recurring = parseColorString(value)
case "scheduled":
styles.Scheduled = parseColorString(value)
case "summary.background":
styles.SummaryBackground = parseColorString(value)
case "summary.bar":
styles.SummaryBar = parseColorString(value)
case "sync.added":
styles.SyncAdded = parseColorString(value)
case "sync.changed":
styles.SyncChanged = parseColorString(value)
case "sync.rejected":
styles.SyncRejected = parseColorString(value)
case "tag.next":
styles.TagNext = parseColorString(value)
case "tag.none":
styles.TagNone = parseColorString(value)
case "tagged":
styles.Tagged = parseColorString(value)
case "uda.priority.H":
styles.UdaPriorityH = parseColorString(value)
case "uda.priority.L":
styles.UdaPriorityL = parseColorString(value)
case "uda.priority.M":
styles.UdaPriorityM = parseColorString(value)
case "undo.after":
styles.UndoAfter = parseColorString(value)
case "undo.before":
styles.UndoBefore = parseColorString(value)
case "until":
styles.Until = parseColorString(value)
case "warning":
styles.Warning = parseColorString(value)
}
_, colorValue, _ := strings.Cut(key, ".")
switch colorValue {
case "active":
styles.Active = parseColorString(value)
case "alternate":
styles.Alternate = parseColorString(value)
case "blocked":
styles.Blocked = parseColorString(value)
case "blocking":
styles.Blocking = parseColorString(value)
case "burndown.done":
styles.BurndownDone = parseColorString(value)
case "burndown.pending":
styles.BurndownPending = parseColorString(value)
case "burndown.started":
styles.BurndownStarted = parseColorString(value)
case "calendar.due":
styles.CalendarDue = parseColorString(value)
case "calendar.due.today":
styles.CalendarDueToday = parseColorString(value)
case "calendar.holiday":
styles.CalendarHoliday = parseColorString(value)
case "calendar.overdue":
styles.CalendarOverdue = parseColorString(value)
case "calendar.scheduled":
styles.CalendarScheduled = parseColorString(value)
case "calendar.today":
styles.CalendarToday = parseColorString(value)
case "calendar.weekend":
styles.CalendarWeekend = parseColorString(value)
case "calendar.weeknumber":
styles.CalendarWeeknumber = parseColorString(value)
case "completed":
styles.Completed = parseColorString(value)
case "debug":
styles.Debug = parseColorString(value)
case "deleted":
styles.Deleted = parseColorString(value)
case "due":
styles.Due = parseColorString(value)
case "due.today":
styles.DueToday = parseColorString(value)
case "error":
styles.Error = parseColorString(value)
case "footnote":
styles.Footnote = parseColorString(value)
case "header":
styles.Header = parseColorString(value)
case "history.add":
styles.HistoryAdd = parseColorString(value)
case "history.delete":
styles.HistoryDelete = parseColorString(value)
case "history.done":
styles.HistoryDone = parseColorString(value)
case "label":
styles.Label = parseColorString(value)
case "label.sort":
styles.LabelSort = parseColorString(value)
case "overdue":
styles.Overdue = parseColorString(value)
case "project.none":
styles.ProjectNone = parseColorString(value)
case "recurring":
styles.Recurring = parseColorString(value)
case "scheduled":
styles.Scheduled = parseColorString(value)
case "summary.background":
styles.SummaryBackground = parseColorString(value)
case "summary.bar":
styles.SummaryBar = parseColorString(value)
case "sync.added":
styles.SyncAdded = parseColorString(value)
case "sync.changed":
styles.SyncChanged = parseColorString(value)
case "sync.rejected":
styles.SyncRejected = parseColorString(value)
case "tag.next":
styles.TagNext = parseColorString(value)
case "tag.none":
styles.TagNone = parseColorString(value)
case "tagged":
styles.Tagged = parseColorString(value)
case "uda.priority.H":
styles.UdaPriorityH = parseColorString(value)
case "uda.priority.L":
styles.UdaPriorityL = parseColorString(value)
case "uda.priority.M":
styles.UdaPriorityM = parseColorString(value)
case "undo.after":
styles.UndoAfter = parseColorString(value)
case "undo.before":
styles.UndoBefore = parseColorString(value)
case "until":
styles.Until = parseColorString(value)
case "warning":
styles.Warning = parseColorString(value)
}
}
}
@ -211,6 +213,10 @@ func parseColors(config map[string]string) *Styles {
func parseColorString(color string) lipgloss.Style {
style := lipgloss.NewStyle()
if color == "" {
return style
}
if strings.Contains(color, "on") {
fgbg := strings.Split(color, "on")
fg := strings.TrimSpace(fgbg[0])
@ -230,12 +236,7 @@ func parseColorString(color string) lipgloss.Style {
func parseColor(color string) lipgloss.Color {
if strings.HasPrefix(color, "rgb") {
rgb, err := parseRGBString(strings.TrimPrefix(color, "rgb"))
if err != nil {
slog.Error("Invalid RGB color format")
return lipgloss.Color("0")
}
return lipgloss.Color(rgbToAnsi(rgb))
return lipgloss.Color(convertRgbToAnsi(strings.TrimPrefix(color, "rgb")))
}
if strings.HasPrefix(color, "color") {
return lipgloss.Color(strings.TrimPrefix(color, "color"))
@ -256,36 +257,33 @@ func parseColor(color string) lipgloss.Color {
return lipgloss.Color("0")
}
type RGB struct {
r int
g int
b int
}
func parseRGBString(rgbString string) (RGB, error) {
func convertRgbToAnsi(rgbString string) string {
var err error
rgb := RGB{}
if len(rgbString) != 3 {
return rgb, errors.New("invalid RGB format")
slog.Error("Invalid RGB color format")
return ""
}
rgb.r, err = strconv.Atoi(string(rgbString[0]))
r, err := strconv.Atoi(string(rgbString[0]))
if err != nil {
return rgb, errors.New("invalid value for R")
slog.Error("Invalid value for R")
return ""
}
rgb.g, err = strconv.Atoi(string(rgbString[1]))
g, err := strconv.Atoi(string(rgbString[1]))
if err != nil {
return rgb, errors.New("invalid value for G")
slog.Error("Invalid value for G")
return ""
}
rgb.b, err = strconv.Atoi(string(rgbString[2]))
b, err := strconv.Atoi(string(rgbString[2]))
if err != nil {
return rgb, errors.New("invalid value for B")
slog.Error("Invalid value for B")
return ""
}
return rgb, nil
return strconv.Itoa(16 + (36 * r) + (6 * g) + b)
}
var colorStrings = map[string]int{
@ -306,79 +304,3 @@ var colorStrings = map[string]int{
"bright cyan": 14,
"bright white": 15,
}
var baseColors = []RGB{
{0, 0, 0}, // Black
{128, 0, 0}, // Red
{0, 128, 0}, // Green
{128, 128, 0}, // Yellow
{0, 0, 128}, // Blue
{128, 0, 128}, // Magenta
{0, 128, 128}, // Cyan
{192, 192, 192}, // White
}
var highIntensityColors = []RGB{
{128, 128, 128}, // Bright Black (Gray)
{255, 0, 0}, // Bright Red
{0, 255, 0}, // Bright Green
{255, 255, 0}, // Bright Yellow
{0, 0, 255}, // Bright Blue
{255, 0, 255}, // Bright Magenta
{0, 255, 255}, // Bright Cyan
{255, 255, 255}, // Bright White
}
// Calculate the Euclidean distance between two colors
func colorDistance(c1, c2 RGB) float64 {
return math.Sqrt(float64((c1.r-c2.r)*(c1.r-c2.r) + (c1.g-c2.g)*(c1.g-c2.g) + (c1.b-c2.b)*(c1.b-c2.b)))
}
// Convert RGB to the nearest ANSI color code
func rgbToAnsi(rgb RGB) string {
// Check standard and high-intensity colors
allColors := append(baseColors, highIntensityColors...)
bestIndex := 0
minDist := colorDistance(rgb, allColors[0])
for i := 1; i < len(allColors); i++ {
dist := colorDistance(rgb, allColors[i])
if dist < minDist {
bestIndex = i
minDist = dist
}
}
if bestIndex < 8 {
return strconv.Itoa(bestIndex)
} else if bestIndex < 16 {
return strconv.Itoa(bestIndex + 8)
}
// Check 6x6x6 color cube
for i := 0; i < 216; i++ {
cubeColor := RGB{
(rgb.r / 51) * 51,
(rgb.g / 51) * 51,
(rgb.b / 51) * 51,
}
dist := colorDistance(rgb, cubeColor)
if dist < minDist {
bestIndex = i + 16
minDist = dist
}
}
// Check grayscale colors
for i := 0; i < 24; i++ {
gray := i*10 + 8
grayColor := RGB{gray, gray, gray}
dist := colorDistance(rgb, grayColor)
if dist < minDist {
bestIndex = i + 232
minDist = dist
}
}
return strconv.Itoa(bestIndex)
}