Clean up task editor and time editor

This commit is contained in:
Martin Pander
2026-02-17 20:57:21 +01:00
parent 6e60698526
commit 1a9fd9b4b0
10 changed files with 141 additions and 115 deletions

View File

@@ -106,13 +106,13 @@ func NewKeymap() *Keymap {
),
NextPage: key.NewBinding(
key.WithKeys("]"),
key.WithHelp("[", "Next page"),
key.WithKeys("]", "L"),
key.WithHelp("]/L", "Next page"),
),
PrevPage: key.NewBinding(
key.WithKeys("["),
key.WithHelp("]", "Previous page"),
key.WithKeys("[", "H"),
key.WithHelp("[/H", "Previous page"),
),
SetReport: key.NewBinding(

View File

@@ -178,7 +178,7 @@ func (t *Task) GetString(fieldWFormat string) string {
return t.Recur
default:
slog.Error(fmt.Sprintf("Field not implemented: %s", field))
slog.Error("Field not implemented", "field", field)
return ""
}
}
@@ -214,7 +214,7 @@ func formatDate(date string, format string) string {
dtformat := "20060102T150405Z"
dt, err := time.Parse(dtformat, date)
if err != nil {
slog.Error("Failed to parse time:", err)
slog.Error("Failed to parse time", "error", err)
return ""
}
@@ -238,7 +238,7 @@ func formatDate(date string, format string) string {
case "countdown":
return parseCountdown(time.Since(dt))
default:
slog.Error(fmt.Sprintf("Date format not implemented: %s", format))
slog.Error("Date format not implemented", "format", format)
return ""
}
}

View File

@@ -40,12 +40,15 @@ func main() {
timewConfigPath = ""
}
ts := taskwarrior.NewTaskSquire(taskrcPath)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
ts := taskwarrior.NewTaskSquire(ctx, taskrcPath)
if ts == nil {
log.Fatal("Failed to initialize TaskSquire. Please check your Taskwarrior installation and taskrc file.")
}
tws := timewarrior.NewTimeSquire(timewConfigPath)
ctx := context.Background()
tws := timewarrior.NewTimeSquire(ctx, timewConfigPath)
common := common.NewCommon(ctx, ts, tws)
file, err := os.OpenFile("/tmp/tasksquire.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)

View File

@@ -3,7 +3,6 @@ package pages
import (
"fmt"
"log/slog"
"strings"
"tasksquire/common"
"time"
@@ -510,6 +509,9 @@ func NewTaskEdit(com *common.Common, task *taskwarrior.Task, isNew bool) *taskEd
udaValues := make(map[string]*string)
for _, uda := range com.Udas {
if uda.Name == "parenttask" {
continue
}
switch uda.Type {
case taskwarrior.UdaTypeNumeric:
val := ""
@@ -691,13 +693,9 @@ type tagEdit struct {
fields []huh.Field
cursor int
newTagsValue *string
}
func NewTagEdit(common *common.Common, selected *[]string, options []string) *tagEdit {
newTags := ""
defaultKeymap := huh.NewDefaultKeyMap()
t := tagEdit{
@@ -711,14 +709,7 @@ func NewTagEdit(common *common.Common, selected *[]string, options []string) *ta
Filterable(true).
WithKeyMap(defaultKeymap).
WithTheme(common.Styles.Form),
huh.NewInput().
Title("New Tags").
Value(&newTags).
Inline(true).
Prompt(": ").
WithTheme(common.Styles.Form),
},
newTagsValue: &newTags,
}
return &t
@@ -1173,13 +1164,6 @@ func (p *TaskEditorPage) updateTasksCmd() tea.Msg {
// p.task.Project = *p.areas[0].(*taskEdit).newProjectName
// }
if *(p.areas[1].(*tagEdit).newTagsValue) != "" {
newTags := strings.Split(*p.areas[1].(*tagEdit).newTagsValue, " ")
if len(newTags) > 0 {
p.task.Tags = append(p.task.Tags, newTags...)
}
}
// Sync timestamp fields from the timeEdit area (area 2)
p.areas[2].(*timeEdit).syncToTaskFields()

View File

@@ -568,7 +568,15 @@ func (p *TimeEditorPage) View() string {
helpStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("8"))
sections = append(sections, helpStyle.Render("tab/shift+tab: navigate • enter: select/save • esc: cancel"))
return lipgloss.JoinVertical(lipgloss.Left, sections...)
content := lipgloss.JoinVertical(lipgloss.Left, sections...)
return lipgloss.Place(
p.common.Width(),
p.common.Height(),
lipgloss.Left,
lipgloss.Top,
content,
)
}
func (p *TimeEditorPage) SetSize(width, height int) {

View File

@@ -229,7 +229,7 @@ func (t *Task) GetString(fieldWFormat string) string {
}
}
slog.Error(fmt.Sprintf("Field not implemented: %s", field))
slog.Error("Field not implemented", "field", field)
return ""
}
@@ -262,7 +262,7 @@ func (t *Task) GetDate(field string) time.Time {
dt, err := time.Parse(dtformat, dateString)
if err != nil {
slog.Error("Failed to parse time:", err)
slog.Error("Failed to parse time", "error", err)
return time.Time{}
}
return dt
@@ -384,7 +384,7 @@ func formatDate(date string, format string) string {
dt, err := time.Parse(dtformat, date)
if err != nil {
slog.Error("Failed to parse time:", err)
slog.Error("Failed to parse time", "error", err)
return ""
}
@@ -408,7 +408,7 @@ func formatDate(date string, format string) string {
case "countdown":
return parseCountdown(time.Since(dt))
default:
slog.Error(fmt.Sprintf("Date format not implemented: %s", format))
slog.Error("Date format not implemented", "format", format)
return ""
}
}

View File

@@ -5,6 +5,7 @@ package taskwarrior
import (
"bytes"
"context"
"encoding/json"
"fmt"
"log/slog"
@@ -111,11 +112,12 @@ type TaskSquire struct {
config *TWConfig
reports Reports
contexts Contexts
ctx context.Context
mutex sync.Mutex
}
func NewTaskSquire(configLocation string) *TaskSquire {
func NewTaskSquire(ctx context.Context, configLocation string) *TaskSquire {
if _, err := exec.LookPath(twBinary); err != nil {
slog.Error("Taskwarrior not found")
return nil
@@ -125,6 +127,7 @@ func NewTaskSquire(configLocation string) *TaskSquire {
ts := &TaskSquire{
configLocation: configLocation,
defaultArgs: defaultArgs,
ctx: ctx,
mutex: sync.Mutex{},
}
ts.config = ts.extractConfig()
@@ -169,17 +172,20 @@ func (ts *TaskSquire) GetTasks(report *Report, filter ...string) Tasks {
exportArgs = append(exportArgs, report.Name)
}
cmd := exec.Command(twBinary, append(args, exportArgs...)...)
cmd := exec.CommandContext(ts.ctx, twBinary, append(args, exportArgs...)...)
output, err := cmd.CombinedOutput()
if err != nil {
slog.Error("Failed getting report:", err)
if ts.ctx.Err() == context.Canceled {
return nil
}
slog.Error("Failed getting report", "error", err)
return nil
}
tasks := make(Tasks, 0)
err = json.Unmarshal(output, &tasks)
if err != nil {
slog.Error("Failed unmarshalling tasks:", err)
slog.Error("Failed unmarshalling tasks", "error", err)
return nil
}
@@ -198,10 +204,10 @@ func (ts *TaskSquire) GetTasks(report *Report, filter ...string) Tasks {
}
func (ts *TaskSquire) getIds(filter []string) string {
cmd := exec.Command(twBinary, append(append(ts.defaultArgs, filter...), "_ids")...)
cmd := exec.CommandContext(ts.ctx, twBinary, append(append(ts.defaultArgs, filter...), "_ids")...)
out, err := cmd.CombinedOutput()
if err != nil {
slog.Error("Failed getting field:", err)
slog.Error("Failed getting field", "error", err)
return ""
}
@@ -219,7 +225,7 @@ func (ts *TaskSquire) GetContext(context string) *Context {
if context, ok := ts.contexts[context]; ok {
return context
} else {
slog.Error(fmt.Sprintf("Context not found: %s", context.Name))
slog.Error("Context not found", "name", context)
return nil
}
}
@@ -248,11 +254,11 @@ func (ts *TaskSquire) GetProjects() []string {
ts.mutex.Lock()
defer ts.mutex.Unlock()
cmd := exec.Command(twBinary, append(ts.defaultArgs, []string{"_projects"}...)...)
cmd := exec.CommandContext(ts.ctx, twBinary, append(ts.defaultArgs, []string{"_projects"}...)...)
output, err := cmd.CombinedOutput()
if err != nil {
slog.Error("Failed getting projects:", err)
slog.Error("Failed getting projects", "error", err)
return nil
}
@@ -286,11 +292,11 @@ func (ts *TaskSquire) GetTags() []string {
ts.mutex.Lock()
defer ts.mutex.Unlock()
cmd := exec.Command(twBinary, append(ts.defaultArgs, []string{"_tags"}...)...)
cmd := exec.CommandContext(ts.ctx, twBinary, append(ts.defaultArgs, []string{"_tags"}...)...)
output, err := cmd.CombinedOutput()
if err != nil {
slog.Error("Failed getting tags:", err)
slog.Error("Failed getting tags", "error", err)
return nil
}
@@ -333,10 +339,13 @@ func (ts *TaskSquire) GetUdas() []Uda {
ts.mutex.Lock()
defer ts.mutex.Unlock()
cmd := exec.Command(twBinary, append(ts.defaultArgs, "_udas")...)
cmd := exec.CommandContext(ts.ctx, twBinary, append(ts.defaultArgs, "_udas")...)
output, err := cmd.CombinedOutput()
if err != nil {
slog.Error("Failed getting config:", err)
if ts.ctx.Err() == context.Canceled {
return nil
}
slog.Error("Failed getting UDAs", "error", err)
return nil
}
@@ -345,7 +354,7 @@ func (ts *TaskSquire) GetUdas() []Uda {
if uda != "" {
udatype := UdaType(ts.config.Get(fmt.Sprintf("uda.%s.type", uda)))
if udatype == "" {
slog.Error(fmt.Sprintf("UDA type not found: %s", uda))
slog.Error("UDA type not found", "uda", uda)
continue
}
@@ -376,9 +385,9 @@ func (ts *TaskSquire) SetContext(context *Context) error {
return nil
}
cmd := exec.Command(twBinary, []string{"context", context.Name}...)
cmd := exec.CommandContext(ts.ctx, twBinary, []string{"context", context.Name}...)
if err := cmd.Run(); err != nil {
slog.Error("Failed setting context:", err)
slog.Error("Failed setting context", "error", err)
return err
}
@@ -433,14 +442,17 @@ func (ts *TaskSquire) ImportTask(task *Task) {
tasks, err := json.Marshal(Tasks{task})
if err != nil {
slog.Error("Failed marshalling task:", err)
slog.Error("Failed marshalling task", "error", err)
}
cmd := exec.Command(twBinary, append(ts.defaultArgs, []string{"import", "-"}...)...)
cmd := exec.CommandContext(ts.ctx, twBinary, append(ts.defaultArgs, []string{"import", "-"}...)...)
cmd.Stdin = bytes.NewBuffer(tasks)
out, err := cmd.CombinedOutput()
if err != nil {
slog.Error("Failed modifying task:", err, string(out))
if ts.ctx.Err() == context.Canceled {
return
}
slog.Error("Failed modifying task", "error", err, "output", string(out))
}
}
@@ -448,10 +460,10 @@ func (ts *TaskSquire) SetTaskDone(task *Task) {
ts.mutex.Lock()
defer ts.mutex.Unlock()
cmd := exec.Command(twBinary, append(ts.defaultArgs, []string{"done", task.Uuid}...)...)
cmd := exec.CommandContext(ts.ctx, twBinary, append(ts.defaultArgs, []string{"done", task.Uuid}...)...)
err := cmd.Run()
if err != nil {
slog.Error("Failed setting task done:", err)
slog.Error("Failed setting task done", "error", err)
}
}
@@ -459,10 +471,10 @@ func (ts *TaskSquire) DeleteTask(task *Task) {
ts.mutex.Lock()
defer ts.mutex.Unlock()
cmd := exec.Command(twBinary, append(ts.defaultArgs, []string{task.Uuid, "delete"}...)...)
cmd := exec.CommandContext(ts.ctx, twBinary, append(ts.defaultArgs, []string{task.Uuid, "delete"}...)...)
err := cmd.Run()
if err != nil {
slog.Error("Failed deleting task:", err)
slog.Error("Failed deleting task", "error", err)
}
}
@@ -471,10 +483,10 @@ func (ts *TaskSquire) Undo() {
ts.mutex.Lock()
defer ts.mutex.Unlock()
cmd := exec.Command(twBinary, append(ts.defaultArgs, []string{"undo"}...)...)
cmd := exec.CommandContext(ts.ctx, twBinary, append(ts.defaultArgs, []string{"undo"}...)...)
err := cmd.Run()
if err != nil {
slog.Error("Failed undoing task:", err)
slog.Error("Failed undoing task", "error", err)
}
}
@@ -482,10 +494,10 @@ func (ts *TaskSquire) StartTask(task *Task) {
ts.mutex.Lock()
defer ts.mutex.Unlock()
cmd := exec.Command(twBinary, append(ts.defaultArgs, []string{"start", task.Uuid}...)...)
cmd := exec.CommandContext(ts.ctx, twBinary, append(ts.defaultArgs, []string{"start", task.Uuid}...)...)
err := cmd.Run()
if err != nil {
slog.Error("Failed starting task:", err)
slog.Error("Failed starting task", "error", err)
}
}
@@ -493,10 +505,10 @@ func (ts *TaskSquire) StopTask(task *Task) {
ts.mutex.Lock()
defer ts.mutex.Unlock()
cmd := exec.Command(twBinary, append(ts.defaultArgs, []string{"stop", task.Uuid}...)...)
cmd := exec.CommandContext(ts.ctx, twBinary, append(ts.defaultArgs, []string{"stop", task.Uuid}...)...)
err := cmd.Run()
if err != nil {
slog.Error("Failed stopping task:", err)
slog.Error("Failed stopping task", "error", err)
}
}
@@ -504,25 +516,28 @@ func (ts *TaskSquire) StopActiveTasks() {
ts.mutex.Lock()
defer ts.mutex.Unlock()
cmd := exec.Command(twBinary, append(ts.defaultArgs, []string{"+ACTIVE", "export"}...)...)
cmd := exec.CommandContext(ts.ctx, twBinary, append(ts.defaultArgs, []string{"+ACTIVE", "export"}...)...)
output, err := cmd.CombinedOutput()
if err != nil {
slog.Error("Failed getting active tasks:", "error", err, "output", string(output))
if ts.ctx.Err() == context.Canceled {
return
}
slog.Error("Failed getting active tasks", "error", err, "output", string(output))
return
}
tasks := make(Tasks, 0)
err = json.Unmarshal(output, &tasks)
if err != nil {
slog.Error("Failed unmarshalling active tasks:", err)
slog.Error("Failed unmarshalling active tasks", "error", err)
return
}
for _, task := range tasks {
cmd := exec.Command(twBinary, append(ts.defaultArgs, []string{"stop", task.Uuid}...)...)
cmd := exec.CommandContext(ts.ctx, twBinary, append(ts.defaultArgs, []string{"stop", task.Uuid}...)...)
err := cmd.Run()
if err != nil {
slog.Error("Failed stopping task:", err)
slog.Error("Failed stopping task", "error", err)
}
}
}
@@ -531,10 +546,13 @@ func (ts *TaskSquire) GetInformation(task *Task) string {
ts.mutex.Lock()
defer ts.mutex.Unlock()
cmd := exec.Command(twBinary, append(ts.defaultArgs, []string{fmt.Sprintf("uuid:%s", task.Uuid), "information"}...)...)
cmd := exec.CommandContext(ts.ctx, twBinary, append(ts.defaultArgs, []string{fmt.Sprintf("uuid:%s", task.Uuid), "information"}...)...)
output, err := cmd.CombinedOutput()
if err != nil {
slog.Error("Failed getting task information:", err)
if ts.ctx.Err() == context.Canceled {
return ""
}
slog.Error("Failed getting task information", "error", err)
return ""
}
@@ -545,17 +563,20 @@ func (ts *TaskSquire) AddTaskAnnotation(uuid string, annotation string) {
ts.mutex.Lock()
defer ts.mutex.Unlock()
cmd := exec.Command(twBinary, append(ts.defaultArgs, []string{uuid, "annotate", annotation}...)...)
cmd := exec.CommandContext(ts.ctx, twBinary, append(ts.defaultArgs, []string{uuid, "annotate", annotation}...)...)
err := cmd.Run()
if err != nil {
slog.Error("Failed adding annotation:", err)
slog.Error("Failed adding annotation", "error", err)
}
}
func (ts *TaskSquire) extractConfig() *TWConfig {
cmd := exec.Command(twBinary, append(ts.defaultArgs, []string{"_show"}...)...)
cmd := exec.CommandContext(ts.ctx, twBinary, append(ts.defaultArgs, []string{"_show"}...)...)
output, err := cmd.CombinedOutput()
if err != nil {
if ts.ctx.Err() == context.Canceled {
return nil
}
slog.Error("Failed getting config", "error", err, "output", string(output))
return nil
}
@@ -564,7 +585,7 @@ func (ts *TaskSquire) extractConfig() *TWConfig {
}
func (ts *TaskSquire) extractReports() Reports {
cmd := exec.Command(twBinary, append(ts.defaultArgs, []string{"_config"}...)...)
cmd := exec.CommandContext(ts.ctx, twBinary, append(ts.defaultArgs, []string{"_config"}...)...)
output, err := cmd.CombinedOutput()
if err != nil {
return nil
@@ -610,10 +631,13 @@ func extractReports(config string) []string {
}
func (ts *TaskSquire) extractContexts() Contexts {
cmd := exec.Command(twBinary, append(ts.defaultArgs, []string{"_context"}...)...)
cmd := exec.CommandContext(ts.ctx, twBinary, append(ts.defaultArgs, []string{"_context"}...)...)
output, err := cmd.CombinedOutput()
if err != nil {
if ts.ctx.Err() == context.Canceled {
return nil
}
slog.Error("Failed getting contexts", "error", err, "output", string(output))
return nil
}

View File

@@ -1,6 +1,7 @@
package taskwarrior
import (
"context"
"fmt"
"os"
"testing"
@@ -56,7 +57,7 @@ func TestTaskSquire_GetContext(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.prep()
ts := NewTaskSquire(tt.fields.configLocation)
ts := NewTaskSquire(context.Background(), tt.fields.configLocation)
if got := ts.GetActiveContext(); got.Name != tt.want {
t.Errorf("TaskSquire.GetContext() = %v, want %v", got, tt.want)
}

View File

@@ -104,7 +104,7 @@ func (i *Interval) GetString(field string) string {
return ""
default:
slog.Error(fmt.Sprintf("Field not implemented: %s", field))
slog.Error("Field not implemented", "field", field)
return ""
}
}
@@ -112,7 +112,7 @@ func (i *Interval) GetString(field string) string {
func (i *Interval) GetDuration() string {
start, err := time.Parse(dtformat, i.Start)
if err != nil {
slog.Error("Failed to parse start time:", err)
slog.Error("Failed to parse start time", "error", err)
return ""
}
@@ -122,7 +122,7 @@ func (i *Interval) GetDuration() string {
} else {
end, err = time.Parse(dtformat, i.End)
if err != nil {
slog.Error("Failed to parse end time:", err)
slog.Error("Failed to parse end time", "error", err)
return ""
}
}
@@ -134,7 +134,7 @@ func (i *Interval) GetDuration() string {
func (i *Interval) GetStartTime() time.Time {
dt, err := time.Parse(dtformat, i.Start)
if err != nil {
slog.Error("Failed to parse time:", err)
slog.Error("Failed to parse time", "error", err)
return time.Time{}
}
return dt
@@ -146,7 +146,7 @@ func (i *Interval) GetEndTime() time.Time {
}
dt, err := time.Parse(dtformat, i.End)
if err != nil {
slog.Error("Failed to parse time:", err)
slog.Error("Failed to parse time", "error", err)
return time.Time{}
}
return dt
@@ -187,7 +187,7 @@ func formatDate(date string, format string) string {
dt, err := time.Parse(dtformat, date)
if err != nil {
slog.Error("Failed to parse time:", err)
slog.Error("Failed to parse time", "error", err)
return ""
}
@@ -211,7 +211,7 @@ func formatDate(date string, format string) string {
case "relative":
return parseDurationVague(time.Until(dt))
default:
slog.Error(fmt.Sprintf("Date format not implemented: %s", format))
slog.Error("Date format not implemented", "format", format)
return ""
}
}

View File

@@ -4,6 +4,7 @@ package timewarrior
import (
"bytes"
"context"
"encoding/json"
"fmt"
"log/slog"
@@ -44,11 +45,12 @@ type TimeSquire struct {
configLocation string
defaultArgs []string
config *TWConfig
ctx context.Context
mutex sync.Mutex
}
func NewTimeSquire(configLocation string) *TimeSquire {
func NewTimeSquire(ctx context.Context, configLocation string) *TimeSquire {
if _, err := exec.LookPath(twBinary); err != nil {
slog.Error("Timewarrior not found")
return nil
@@ -57,6 +59,7 @@ func NewTimeSquire(configLocation string) *TimeSquire {
ts := &TimeSquire{
configLocation: configLocation,
defaultArgs: []string{},
ctx: ctx,
mutex: sync.Mutex{},
}
ts.config = ts.extractConfig()
@@ -75,11 +78,11 @@ func (ts *TimeSquire) GetTags() []string {
ts.mutex.Lock()
defer ts.mutex.Unlock()
cmd := exec.Command(twBinary, append(ts.defaultArgs, []string{"tags"}...)...)
cmd := exec.CommandContext(ts.ctx, twBinary, append(ts.defaultArgs, []string{"tags"}...)...)
output, err := cmd.CombinedOutput()
if err != nil {
slog.Error("Failed getting tags:", err)
slog.Error("Failed getting tags", "error", err)
return nil
}
@@ -150,17 +153,20 @@ func (ts *TimeSquire) getIntervalsUnlocked(filter ...string) Intervals {
args = append(args, filter...)
}
cmd := exec.Command(twBinary, args...)
cmd := exec.CommandContext(ts.ctx, twBinary, args...)
output, err := cmd.CombinedOutput()
if err != nil {
slog.Error("Failed getting intervals:", err)
if ts.ctx.Err() == context.Canceled {
return nil
}
slog.Error("Failed getting intervals", "error", err)
return nil
}
intervals := make(Intervals, 0)
err = json.Unmarshal(output, &intervals)
if err != nil {
slog.Error("Failed unmarshalling intervals:", err)
slog.Error("Failed unmarshalling intervals", "error", err)
return nil
}
@@ -194,9 +200,9 @@ func (ts *TimeSquire) StartTracking(tags []string) error {
args := append(ts.defaultArgs, "start")
args = append(args, tags...)
cmd := exec.Command(twBinary, args...)
cmd := exec.CommandContext(ts.ctx, twBinary, args...)
if err := cmd.Run(); err != nil {
slog.Error("Failed starting tracking:", err)
slog.Error("Failed starting tracking", "error", err)
return err
}
@@ -207,9 +213,9 @@ func (ts *TimeSquire) StopTracking() error {
ts.mutex.Lock()
defer ts.mutex.Unlock()
cmd := exec.Command(twBinary, append(ts.defaultArgs, "stop")...)
cmd := exec.CommandContext(ts.ctx, twBinary, append(ts.defaultArgs, "stop")...)
if err := cmd.Run(); err != nil {
slog.Error("Failed stopping tracking:", err)
slog.Error("Failed stopping tracking", "error", err)
return err
}
@@ -220,9 +226,9 @@ func (ts *TimeSquire) ContinueTracking() error {
ts.mutex.Lock()
defer ts.mutex.Unlock()
cmd := exec.Command(twBinary, append(ts.defaultArgs, "continue")...)
cmd := exec.CommandContext(ts.ctx, twBinary, append(ts.defaultArgs, "continue")...)
if err := cmd.Run(); err != nil {
slog.Error("Failed continuing tracking:", err)
slog.Error("Failed continuing tracking", "error", err)
return err
}
@@ -233,9 +239,9 @@ func (ts *TimeSquire) ContinueInterval(id int) error {
ts.mutex.Lock()
defer ts.mutex.Unlock()
cmd := exec.Command(twBinary, append(ts.defaultArgs, []string{"continue", fmt.Sprintf("@%d", id)}...)...)
cmd := exec.CommandContext(ts.ctx, twBinary, append(ts.defaultArgs, []string{"continue", fmt.Sprintf("@%d", id)}...)...)
if err := cmd.Run(); err != nil {
slog.Error("Failed continuing interval:", err)
slog.Error("Failed continuing interval", "error", err)
return err
}
@@ -246,9 +252,9 @@ func (ts *TimeSquire) CancelTracking() error {
ts.mutex.Lock()
defer ts.mutex.Unlock()
cmd := exec.Command(twBinary, append(ts.defaultArgs, "cancel")...)
cmd := exec.CommandContext(ts.ctx, twBinary, append(ts.defaultArgs, "cancel")...)
if err := cmd.Run(); err != nil {
slog.Error("Failed canceling tracking:", err)
slog.Error("Failed canceling tracking", "error", err)
return err
}
@@ -259,9 +265,9 @@ func (ts *TimeSquire) DeleteInterval(id int) error {
ts.mutex.Lock()
defer ts.mutex.Unlock()
cmd := exec.Command(twBinary, append(ts.defaultArgs, []string{"delete", fmt.Sprintf("@%d", id)}...)...)
cmd := exec.CommandContext(ts.ctx, twBinary, append(ts.defaultArgs, []string{"delete", fmt.Sprintf("@%d", id)}...)...)
if err := cmd.Run(); err != nil {
slog.Error("Failed deleting interval:", err)
slog.Error("Failed deleting interval", "error", err)
return err
}
@@ -272,9 +278,9 @@ func (ts *TimeSquire) FillInterval(id int) error {
ts.mutex.Lock()
defer ts.mutex.Unlock()
cmd := exec.Command(twBinary, append(ts.defaultArgs, []string{"fill", fmt.Sprintf("@%d", id)}...)...)
cmd := exec.CommandContext(ts.ctx, twBinary, append(ts.defaultArgs, []string{"fill", fmt.Sprintf("@%d", id)}...)...)
if err := cmd.Run(); err != nil {
slog.Error("Failed filling interval:", err)
slog.Error("Failed filling interval", "error", err)
return err
}
@@ -287,9 +293,9 @@ func (ts *TimeSquire) JoinInterval(id int) error {
// Join the current interval with the previous one
// The previous interval has id+1 (since intervals are ordered newest first)
cmd := exec.Command(twBinary, append(ts.defaultArgs, []string{"join", fmt.Sprintf("@%d", id+1), fmt.Sprintf("@%d", id)}...)...)
cmd := exec.CommandContext(ts.ctx, twBinary, append(ts.defaultArgs, []string{"join", fmt.Sprintf("@%d", id+1), fmt.Sprintf("@%d", id)}...)...)
if err := cmd.Run(); err != nil {
slog.Error("Failed joining interval:", err)
slog.Error("Failed joining interval", "error", err)
return err
}
@@ -303,7 +309,7 @@ func (ts *TimeSquire) ModifyInterval(interval *Interval, adjust bool) error {
// Export the modified interval
intervals, err := json.Marshal(Intervals{interval})
if err != nil {
slog.Error("Failed marshalling interval:", err)
slog.Error("Failed marshalling interval", "error", err)
return err
}
@@ -314,11 +320,11 @@ func (ts *TimeSquire) ModifyInterval(interval *Interval, adjust bool) error {
}
// Import the modified interval
cmd := exec.Command(twBinary, args...)
cmd := exec.CommandContext(ts.ctx, twBinary, args...)
cmd.Stdin = bytes.NewBuffer(intervals)
out, err := cmd.CombinedOutput()
if err != nil {
slog.Error("Failed modifying interval:", err, string(out))
slog.Error("Failed modifying interval", "error", err, "output", string(out))
return err
}
@@ -334,10 +340,10 @@ func (ts *TimeSquire) GetSummary(filter ...string) string {
args = append(args, filter...)
}
cmd := exec.Command(twBinary, args...)
cmd := exec.CommandContext(ts.ctx, twBinary, args...)
output, err := cmd.CombinedOutput()
if err != nil {
slog.Error("Failed getting summary:", err)
slog.Error("Failed getting summary", "error", err)
return ""
}
@@ -348,7 +354,7 @@ func (ts *TimeSquire) GetActive() *Interval {
ts.mutex.Lock()
defer ts.mutex.Unlock()
cmd := exec.Command(twBinary, append(ts.defaultArgs, []string{"get", "dom.active"}...)...)
cmd := exec.CommandContext(ts.ctx, twBinary, append(ts.defaultArgs, []string{"get", "dom.active"}...)...)
output, err := cmd.CombinedOutput()
if err != nil || string(output) == "0\n" {
return nil
@@ -369,18 +375,18 @@ func (ts *TimeSquire) Undo() {
ts.mutex.Lock()
defer ts.mutex.Unlock()
cmd := exec.Command(twBinary, append(ts.defaultArgs, []string{"undo"}...)...)
cmd := exec.CommandContext(ts.ctx, twBinary, append(ts.defaultArgs, []string{"undo"}...)...)
err := cmd.Run()
if err != nil {
slog.Error("Failed undoing:", err)
slog.Error("Failed undoing", "error", err)
}
}
func (ts *TimeSquire) extractConfig() *TWConfig {
cmd := exec.Command(twBinary, append(ts.defaultArgs, []string{"show"}...)...)
cmd := exec.CommandContext(ts.ctx, twBinary, append(ts.defaultArgs, []string{"show"}...)...)
output, err := cmd.CombinedOutput()
if err != nil {
slog.Error("Failed getting config:", err)
slog.Error("Failed getting config", "error", err)
return nil
}