Fix UDA colors

This commit is contained in:
Martin
2024-05-31 13:40:49 +02:00
parent 035d09900e
commit 9aa7b04b98
8 changed files with 110 additions and 39 deletions

View File

@ -15,6 +15,7 @@ type Common struct {
TW taskwarrior.TaskWarrior TW taskwarrior.TaskWarrior
Keymap *Keymap Keymap *Keymap
Styles *Styles Styles *Styles
Udas []string
pageStack *Stack[Component] pageStack *Stack[Component]
width int width int
@ -27,6 +28,7 @@ func NewCommon(ctx context.Context, tw taskwarrior.TaskWarrior) *Common {
TW: tw, TW: tw,
Keymap: NewKeymap(), Keymap: NewKeymap(),
Styles: NewStyles(tw.GetConfig()), Styles: NewStyles(tw.GetConfig()),
Udas: tw.GetUdas(),
pageStack: NewStack[Component](), pageStack: NewStack[Component](),
} }

View File

@ -29,6 +29,8 @@ type Styles struct {
ColumnBlurred lipgloss.Style ColumnBlurred lipgloss.Style
ColumnInsert lipgloss.Style ColumnInsert lipgloss.Style
Colors map[string]lipgloss.Style
// TODO: make color config completely dynamic to account for keyword., project., tag. and uda. colors // TODO: make color config completely dynamic to account for keyword., project., tag. and uda. colors
Active lipgloss.Style Active lipgloss.Style
Alternate lipgloss.Style Alternate lipgloss.Style
@ -114,10 +116,12 @@ func NewStyles(config *taskwarrior.TWConfig) *Styles {
func parseColors(config map[string]string) *Styles { func parseColors(config map[string]string) *Styles {
styles := Styles{} styles := Styles{}
colors := make(map[string]lipgloss.Style)
for key, value := range config { for key, value := range config {
if strings.HasPrefix(key, "color.") { if strings.HasPrefix(key, "color.") {
_, colorValue, _ := strings.Cut(key, ".") _, colorValue, _ := strings.Cut(key, ".")
colors[colorValue] = parseColorString(value)
switch colorValue { switch colorValue {
case "active": case "active":
styles.Active = parseColorString(value) styles.Active = parseColorString(value)
@ -217,6 +221,8 @@ func parseColors(config map[string]string) *Styles {
} }
} }
styles.Colors = colors
return &styles return &styles
} }

View File

@ -1,6 +1,7 @@
package table package table
import ( import (
"fmt"
"strings" "strings"
"time" "time"
@ -189,6 +190,18 @@ func (m *Model) parseRowStyles(rows taskwarrior.Tasks) []lipgloss.Style {
styles[i] = m.common.Styles.Recurring.Inherit(m.styles.Cell).Margin(m.styles.Cell.GetMargin()).Padding(m.styles.Cell.GetPadding()) styles[i] = m.common.Styles.Recurring.Inherit(m.styles.Cell).Margin(m.styles.Cell.GetMargin()).Padding(m.styles.Cell.GetPadding())
continue continue
} }
// TOOD: move udas to proper location
if len(m.common.Udas) > 0 {
for _, uda := range m.common.Udas {
if u, ok := task.Udas[uda]; ok {
if style, ok := m.common.Styles.Colors[fmt.Sprintf("uda.%s.%s", uda, u)]; ok {
styles[i] = style.Inherit(m.styles.Cell).Margin(m.styles.Cell.GetMargin()).Padding(m.styles.Cell.GetPadding())
}
}
}
continue
}
// TODO: make styles optional and discard if empty
if len(task.Tags) > 0 { if len(task.Tags) > 0 {
styles[i] = m.common.Styles.Tagged.Inherit(m.styles.Cell).Margin(m.styles.Cell.GetMargin()).Padding(m.styles.Cell.GetPadding()) styles[i] = m.common.Styles.Tagged.Inherit(m.styles.Cell).Margin(m.styles.Cell.GetMargin()).Padding(m.styles.Cell.GetPadding())
taskIteration: taskIteration:
@ -200,7 +213,6 @@ func (m *Model) parseRowStyles(rows taskwarrior.Tasks) []lipgloss.Style {
} }
continue continue
} }
// TODO implement uda
styles[i] = m.common.Styles.Base.Inherit(m.styles.Cell).Margin(m.styles.Cell.GetMargin()).Padding(m.styles.Cell.GetPadding()) styles[i] = m.common.Styles.Base.Inherit(m.styles.Cell).Margin(m.styles.Cell.GetMargin()).Padding(m.styles.Cell.GetPadding())
} }
return styles return styles

View File

@ -3,7 +3,6 @@ package pages
import ( import (
"fmt" "fmt"
"log/slog" "log/slog"
"slices"
"strings" "strings"
"tasksquire/common" "tasksquire/common"
@ -52,8 +51,6 @@ func NewTaskEditorPage(com *common.Common, task taskwarrior.Task) *TaskEditorPag
priorityOptions := append([]string{"(none)"}, p.common.TW.GetPriorities()...) priorityOptions := append([]string{"(none)"}, p.common.TW.GetPriorities()...)
projectOptions := append([]string{"(none)"}, p.common.TW.GetProjects()...) projectOptions := append([]string{"(none)"}, p.common.TW.GetProjects()...)
tagOptions := p.common.TW.GetTags() tagOptions := p.common.TW.GetTags()
tagOptions = append(tagOptions, strings.Split(p.common.TW.GetConfig().Get("uda.tasksquire.tags.default"), ",")...)
slices.Sort(tagOptions)
p.areas = map[area]tea.Model{ p.areas = map[area]tea.Model{
areaTask: NewTaskEdit(p.common, &p.task.Description, &p.task.Priority, &p.task.Project, priorityOptions, projectOptions), areaTask: NewTaskEdit(p.common, &p.task.Description, &p.task.Priority, &p.task.Project, priorityOptions, projectOptions),
@ -459,11 +456,11 @@ func NewTaskEdit(common *common.Common, description *string, priority *string, p
return &t return &t
} }
func (t taskEdit) Init() tea.Cmd { func (t *taskEdit) Init() tea.Cmd {
return nil return nil
} }
func (t taskEdit) Update(msg tea.Msg) (tea.Model, tea.Cmd) { func (t *taskEdit) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg.(type) { switch msg.(type) {
case nextFieldMsg: case nextFieldMsg:
if t.cursor == len(t.fields)-1 { if t.cursor == len(t.fields)-1 {
@ -490,7 +487,7 @@ func (t taskEdit) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return t, nil return t, nil
} }
func (t taskEdit) View() string { func (t *taskEdit) View() string {
views := make([]string, len(t.fields)) views := make([]string, len(t.fields))
for i, field := range t.fields { for i, field := range t.fields {
views[i] = field.View() views[i] = field.View()
@ -540,11 +537,11 @@ func NewTagEdit(common *common.Common, selected *[]string, options []string) *ta
return &t return &t
} }
func (t tagEdit) Init() tea.Cmd { func (t *tagEdit) Init() tea.Cmd {
return nil return nil
} }
func (t tagEdit) Update(msg tea.Msg) (tea.Model, tea.Cmd) { func (t *tagEdit) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg.(type) { switch msg.(type) {
case nextFieldMsg: case nextFieldMsg:
if t.cursor == len(t.fields)-1 { if t.cursor == len(t.fields)-1 {
@ -625,11 +622,11 @@ func NewTimeEdit(common *common.Common, due *string, scheduled *string, wait *st
return &t return &t
} }
func (t timeEdit) Init() tea.Cmd { func (t *timeEdit) Init() tea.Cmd {
return nil return nil
} }
func (t timeEdit) Update(msg tea.Msg) (tea.Model, tea.Cmd) { func (t *timeEdit) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg.(type) { switch msg.(type) {
case nextFieldMsg: case nextFieldMsg:
if t.cursor == len(t.fields)-1 { if t.cursor == len(t.fields)-1 {
@ -655,7 +652,7 @@ func (t timeEdit) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return t, nil return t, nil
} }
func (t timeEdit) View() string { func (t *timeEdit) View() string {
views := make([]string, len(t.fields)) views := make([]string, len(t.fields))
for i, field := range t.fields { for i, field := range t.fields {
views[i] = field.View() views[i] = field.View()
@ -796,12 +793,15 @@ func (p *TaskEditorPage) updateTasksCmd() tea.Msg {
p.task.Priority = "" p.task.Priority = ""
} }
if *p.areas[areaTask].(taskEdit).newProjectName != "" { if *(p.areas[areaTask].(*taskEdit).newProjectName) != "" {
p.task.Project = *p.areas[areaTask].(taskEdit).newProjectName p.task.Project = *p.areas[areaTask].(*taskEdit).newProjectName
} }
if *p.areas[areaTags].(tagEdit).newTagsValue != "" { if *(p.areas[areaTags].(*tagEdit).newTagsValue) != "" {
p.task.Tags = append(p.task.Tags, strings.Split(*p.areas[areaTags].(tagEdit).newTagsValue, " ")...) newTags := strings.Split(*p.areas[areaTags].(*tagEdit).newTagsValue, " ")
if len(newTags) > 0 {
p.task.Tags = append(p.task.Tags, newTags...)
}
} }
// if p.additionalProject != "" { // if p.additionalProject != "" {

View File

@ -23,28 +23,29 @@ func (a Annotation) String() string {
} }
type Task struct { type Task struct {
Id int64 `json:"id,omitempty"` Id int64 `json:"id,omitempty"`
Uuid string `json:"uuid,omitempty"` Uuid string `json:"uuid,omitempty"`
Description string `json:"description,omitempty"` Description string `json:"description,omitempty"`
Project string `json:"project"` Project string `json:"project"`
Priority string `json:"priority"` Priority string `json:"priority"`
Status string `json:"status,omitempty"` Status string `json:"status,omitempty"`
Tags []string `json:"tags"` Tags []string `json:"tags"`
VirtualTags []string `json:"-"` VirtualTags []string `json:"-"`
Depends []string `json:"depends,omitempty"` Depends []string `json:"depends,omitempty"`
DependsIds string `json:"-"` DependsIds string `json:"-"`
Urgency float32 `json:"urgency,omitempty"` Urgency float32 `json:"urgency,omitempty"`
Parent string `json:"parent,omitempty"` Parent string `json:"parent,omitempty"`
Due string `json:"due,omitempty"` Due string `json:"due,omitempty"`
Wait string `json:"wait,omitempty"` Wait string `json:"wait,omitempty"`
Scheduled string `json:"scheduled,omitempty"` Scheduled string `json:"scheduled,omitempty"`
Until string `json:"until,omitempty"` Until string `json:"until,omitempty"`
Start string `json:"start,omitempty"` Start string `json:"start,omitempty"`
End string `json:"end,omitempty"` End string `json:"end,omitempty"`
Entry string `json:"entry,omitempty"` Entry string `json:"entry,omitempty"`
Modified string `json:"modified,omitempty"` Modified string `json:"modified,omitempty"`
Recur string `json:"recur,omitempty"` Recur string `json:"recur,omitempty"`
Annotations []Annotation `json:"annotations,omitempty"` Annotations []Annotation `json:"annotations,omitempty"`
Udas map[string]any `json:"-"`
} }
func (t *Task) GetString(fieldWFormat string) string { func (t *Task) GetString(fieldWFormat string) string {

View File

@ -89,6 +89,8 @@ type TaskWarrior interface {
GetReport(report string) *Report GetReport(report string) *Report
GetReports() Reports GetReports() Reports
GetUdas() []string
GetTasks(report *Report, filter ...string) Tasks GetTasks(report *Report, filter ...string) Tasks
AddTask(task *Task) error AddTask(task *Task) error
ImportTask(task *Task) ImportTask(task *Task)
@ -169,7 +171,15 @@ func (ts *TaskSquire) GetTasks(report *Report, filter ...string) Tasks {
return nil return nil
} }
for _, task := range tasks { unstructuredTasks := make([]map[string]any, 0)
err = json.Unmarshal(output, &unstructuredTasks)
if err != nil {
slog.Error("Failed unmarshalling tasks:", err)
return nil
}
for i, task := range tasks {
task.Udas = unstructuredTasks[i]
if task.Depends != nil && len(task.Depends) > 0 { if task.Depends != nil && len(task.Depends) > 0 {
ids := make([]string, len(task.Depends)) ids := make([]string, len(task.Depends))
for i, dependUuid := range task.Depends { for i, dependUuid := range task.Depends {
@ -281,10 +291,18 @@ func (ts *TaskSquire) GetTags() []string {
} }
tags := make([]string, 0) tags := make([]string, 0)
tagSet := make(map[string]struct{})
for _, tag := range strings.Split(string(output), "\n") { for _, tag := range strings.Split(string(output), "\n") {
if _, ok := virtualTags[tag]; !ok && tag != "" { if _, ok := virtualTags[tag]; !ok && tag != "" {
tags = append(tags, tag) tags = append(tags, tag)
tagSet[tag] = struct{}{}
}
}
for _, tag := range strings.Split(ts.config.Get("uda.tasksquire.tags.default"), ",") {
if _, ok := tagSet[tag]; !ok {
tags = append(tags, tag)
} }
} }
@ -307,6 +325,27 @@ func (ts *TaskSquire) GetReports() Reports {
return ts.reports return ts.reports
} }
func (ts *TaskSquire) GetUdas() []string {
ts.mutex.Lock()
defer ts.mutex.Unlock()
cmd := exec.Command(twBinary, append(ts.defaultArgs, "_udas")...)
output, err := cmd.CombinedOutput()
if err != nil {
slog.Error("Failed getting config:", err)
return nil
}
udas := make([]string, 0)
for _, uda := range strings.Split(string(output), "\n") {
if uda != "" {
udas = append(udas, uda)
}
}
return udas
}
func (ts *TaskSquire) SetContext(context *Context) error { func (ts *TaskSquire) SetContext(context *Context) error {
ts.mutex.Lock() ts.mutex.Lock()
defer ts.mutex.Unlock() defer ts.mutex.Unlock()

Binary file not shown.

View File

@ -4,3 +4,14 @@ context.test.read=+test
context.test.write=+test context.test.write=+test
context.home.read=+home context.home.read=+home
context.home.write=+home context.home.write=+home
uda.testuda.type=string
uda.testuda.label=testuda
uda.testuda.values=eins,zwei,drei
report.next.columns=id,testuda,start.age,entry.age,depends,priority,project,tags,recur,scheduled.countdown,due.relative,until.remaining,description,urgency
report.next.context=1
report.next.description=Most urgent tasks
report.next.filter=status:pending -WAITING
report.next.labels=ID,UDA,Active,Age,Deps,P,Project,Tag,Recur,S,Due,Until,Description,Urg
report.next.sort=urgency-