summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-03-03 23:20:17 +0200
committerPaul Buetow <paul@buetow.org>2026-03-03 23:20:30 +0200
commit991f31649cf97a94a04c6e9862acab042cbedec0 (patch)
treed42208f281db952691e4418cdb048c2d8ce0d793
parentb3dfd2441f1448eaa21d0e92346dbb966ccc5163 (diff)
bump up version to 0.11.2
Patch release: code quality improvements based on 100 Go Mistakes analysis. - Fixed race condition in global RNG - Optimized render performance by lazy-calling .View() - Improved map pre-allocation - Handled or explicitly silenced unchecked errors - Removed unused functions and fields - Updated deprecated library methods
-rw-r--r--TODO.md3
-rw-r--r--internal/task/task.go2
-rw-r--r--internal/ui/handlers.go16
-rw-r--r--internal/ui/helpers.go20
-rw-r--r--internal/ui/keyhandlers.go10
-rw-r--r--internal/ui/table.go107
-rw-r--r--internal/ui/theme.go3
7 files changed, 44 insertions, 117 deletions
diff --git a/TODO.md b/TODO.md
deleted file mode 100644
index 9a61cff..0000000
--- a/TODO.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# To-do's
-
-* As of now nothing here.
diff --git a/internal/task/task.go b/internal/task/task.go
index d8e2e72..51d1451 100644
--- a/internal/task/task.go
+++ b/internal/task/task.go
@@ -61,7 +61,7 @@ var dbg debugConfig
func SetDebugLog(path string) error {
// Close existing debug file if open before re-configuring.
if dbg.file != nil {
- dbg.file.Close()
+ _ = dbg.file.Close()
dbg.file = nil
dbg.writer = nil
}
diff --git a/internal/ui/handlers.go b/internal/ui/handlers.go
index d447c31..11a78cd 100644
--- a/internal/ui/handlers.go
+++ b/internal/ui/handlers.go
@@ -58,7 +58,7 @@ func (m *Model) handleAnnotationMode(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
return err
}
}
- m.reload()
+ _ = m.reload()
return nil
}
@@ -84,7 +84,7 @@ func (m *Model) handleDescriptionMode(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
if err := task.SetDescription(m.descID, value); err != nil {
return err
}
- m.reload()
+ _ = m.reload()
return nil
}
@@ -114,9 +114,7 @@ func (m *Model) handleTagsMode(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
removes = append(removes, tagName)
}
} else {
- if strings.HasPrefix(w, "+") {
- w = w[1:]
- }
+ w = strings.TrimPrefix(w, "+")
if w != "" {
if err := validateTagName(w); err != nil {
return fmt.Errorf("add tag '%s': %w", w, err)
@@ -135,7 +133,7 @@ func (m *Model) handleTagsMode(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
return err
}
}
- m.reload()
+ _ = m.reload()
return nil
}
@@ -204,7 +202,7 @@ func (m *Model) handleRecurrenceMode(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
if err := task.SetRecurrence(m.recurID, value); err != nil {
return err
}
- m.reload()
+ _ = m.reload()
return nil
}
@@ -298,7 +296,7 @@ func (m *Model) handlePriorityMode(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
func (m *Model) handleFilterMode(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
onEnter := func(value string) error {
m.filters = strings.Fields(value)
- m.reload()
+ _ = m.reload()
return nil
}
@@ -313,7 +311,7 @@ func (m *Model) handleFilterMode(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
func (m *Model) handleAddTaskMode(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
switch msg.Type {
case tea.KeyEnter:
- oldIDs := make(map[int]struct{})
+ oldIDs := make(map[int]struct{}, len(m.tasks))
for _, tsk := range m.tasks {
oldIDs[tsk.ID] = struct{}{}
}
diff --git a/internal/ui/helpers.go b/internal/ui/helpers.go
index 9846811..4cdf3cc 100644
--- a/internal/ui/helpers.go
+++ b/internal/ui/helpers.go
@@ -22,16 +22,6 @@ func parseTaskDate(dateStr string) (time.Time, error) {
return time.Parse(taskDateFormat, dateStr)
}
-// formatTaskDate formats a time as a Taskwarrior date string
-func formatTaskDate(t time.Time) string {
- return t.UTC().Format(taskDateFormat)
-}
-
-// daysSince returns the number of days since the given time
-func daysSince(t time.Time) int {
- return int(time.Since(t).Hours() / 24)
-}
-
// daysUntil returns the number of days until the given time
func daysUntil(t time.Time) int {
now := time.Now()
@@ -101,16 +91,6 @@ func validateTagName(tag string) error {
return nil
}
-// validateTags validates a list of tags
-func validateTags(tags []string) error {
- for _, tag := range tags {
- if err := validateTagName(tag); err != nil {
- return fmt.Errorf("invalid tag '%s': %w", tag, err)
- }
- }
- return nil
-}
-
// validateDueDate validates a due date string
func validateDueDate(due string) error {
if due == "" {
diff --git a/internal/ui/keyhandlers.go b/internal/ui/keyhandlers.go
index 3db0725..0a2bc62 100644
--- a/internal/ui/keyhandlers.go
+++ b/internal/ui/keyhandlers.go
@@ -28,16 +28,16 @@ func (m *Model) handleNormalMode(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
case "N":
return m.handlePrevHelpSearchMatch()
case "up", "k":
- m.helpViewport.LineUp(1)
+ m.helpViewport.ScrollUp(1)
return m, nil
case "down", "j":
- m.helpViewport.LineDown(1)
+ m.helpViewport.ScrollDown(1)
return m, nil
case "pgup", "b":
- m.helpViewport.ViewUp()
+ m.helpViewport.PageUp()
return m, nil
case "pgdown", " ":
- m.helpViewport.ViewDown()
+ m.helpViewport.PageDown()
return m, nil
case "g", "home":
m.helpViewport.GotoTop()
@@ -337,7 +337,7 @@ func (m *Model) handleRandomDueDate() (tea.Model, tea.Cmd) {
return m, nil
}
- days := rng.Intn(31) + 7
+ days := rand.Intn(31) + 7
due := time.Now().AddDate(0, 0, days).Format("2006-01-02")
if err := task.SetDueDate(id, due); err != nil {
diff --git a/internal/ui/table.go b/internal/ui/table.go
index bfdc803..05c0548 100644
--- a/internal/ui/table.go
+++ b/internal/ui/table.go
@@ -2,7 +2,6 @@ package ui
import (
"fmt"
- "math/rand"
"os"
"os/exec"
"regexp"
@@ -27,7 +26,6 @@ var priorityOptions = []string{"H", "M", "L", ""}
var (
urlRegex = regexp.MustCompile(`https?://\S+`)
searchRegexCache = make(map[string]*regexp.Regexp)
- rng = rand.New(rand.NewSource(time.Now().UnixNano()))
)
type cellMatch struct {
@@ -78,7 +76,6 @@ type detailViewState struct {
// detailDescEditing lives here (not in editState) because it drives an
// external-editor launch from the detail overlay, not inline text input.
detailDescEditing bool // whether the description editor is open
- detailDescTempFile string // temp file path for description editing
}
// editState holds inline field-editing state for the task table.
@@ -208,9 +205,9 @@ func editDescriptionCmd(description string) tea.Cmd {
// Write current description to temp file
_, err = tmpFile.WriteString(description)
- tmpFile.Close()
+ _ = tmpFile.Close()
if err != nil {
- os.Remove(tmpPath)
+ _ = os.Remove(tmpPath)
return descEditDoneMsg{err: err, tempFile: ""}
}
@@ -524,7 +521,7 @@ func (m *Model) handleEditDone(msg editDoneMsg) (tea.Model, tea.Cmd) {
// handleDescEditDone handles the completion of description editing
func (m *Model) handleDescEditDone(msg descEditDoneMsg) (tea.Model, tea.Cmd) {
m.detailDescEditing = false
- defer os.Remove(msg.tempFile) // Clean up temp file
+ _ = os.Remove(msg.tempFile) // Clean up temp file
if msg.err != nil {
m.statusMsg = fmt.Sprintf("Edit error: %v", msg.err)
@@ -642,26 +639,32 @@ func (m Model) View() string {
// (annotate, due, priority, desc, tags, recur, project, filter, add, search)
// should be displayed below the table. At most one is active at a time.
func (m Model) appendInlineInputOverlay(view string) string {
- type overlay struct {
- active bool
- widget string
- }
- overlays := []overlay{
- {m.annotating, m.annotateInput.View()},
- {m.dueEditing, m.dueView(true)},
- {m.prioritySelecting, m.priorityView(true)},
- {m.descEditing, m.descInput.View()},
- {m.tagsEditing, m.tagsInput.View()},
- {m.recurEditing, m.recurInput.View()},
- {m.projEditing, m.projInput.View()},
- {m.filterEditing, m.filterInput.View()},
- {m.addingTask, m.addInput.View()},
- {m.searching, m.searchInput.View()},
- }
- for _, o := range overlays {
- if o.active {
- view = lipgloss.JoinVertical(lipgloss.Left, view, o.widget)
- }
+ var overlay string
+ switch {
+ case m.annotating:
+ overlay = m.annotateInput.View()
+ case m.dueEditing:
+ overlay = m.dueView(true)
+ case m.prioritySelecting:
+ overlay = m.priorityView(true)
+ case m.descEditing:
+ overlay = m.descInput.View()
+ case m.tagsEditing:
+ overlay = m.tagsInput.View()
+ case m.recurEditing:
+ overlay = m.recurInput.View()
+ case m.projEditing:
+ overlay = m.projInput.View()
+ case m.filterEditing:
+ overlay = m.filterInput.View()
+ case m.addingTask:
+ overlay = m.addInput.View()
+ case m.searching:
+ overlay = m.searchInput.View()
+ }
+
+ if overlay != "" {
+ view = lipgloss.JoinVertical(lipgloss.Left, view, overlay)
}
return view
}
@@ -888,49 +891,6 @@ func (m Model) topStatusLine() string {
Render(line)
}
-func (m Model) taskToRow(t task.Task) atable.Row {
- style := lipgloss.NewStyle()
- if t.Start != "" {
- style = style.Background(lipgloss.Color(m.theme.StartBG))
- }
- if t.ID == m.blinkID && m.blinkOn {
- style = style.Reverse(true)
- }
-
- age := ""
- if ts, err := time.Parse(task.DateFormat, t.Entry); err == nil {
- days := int(time.Since(ts).Hours() / 24)
- age = fmt.Sprintf("%dd", days)
- }
-
- tags := strings.Join(t.Tags, " ")
- urg := fmt.Sprintf("%.1f", t.Urgency)
- recur := t.Recur
-
- var anns []string
- for _, a := range t.Annotations {
- anns = append(anns, a.Description)
- }
-
- annStr := ""
- if n := len(anns); n > 0 {
- annStr = strconv.FormatInt(int64(n), 16)
- }
-
- return atable.Row{
- m.formatPriority(t.Priority, m.priWidth),
- style.Render(strconv.Itoa(t.ID)),
- style.Render(age),
- m.formatDue(t.Due, m.dueWidth),
- style.Render(recur),
- style.Render(t.Project),
- style.Render(tags),
- style.Render(annStr),
- style.Render(t.Description),
- style.Render(m.formatUrgency(urg, m.urgWidth)),
- }
-}
-
// formatDue returns a formatted due date string. Dates due today or tomorrow
// are returned as "today" or "tomorrow" respectively. Past due dates are
// highlighted in red.
@@ -1292,12 +1252,3 @@ func (m *Model) applyTheme() {
func (m *Model) SetDisco(d bool) {
m.disco = d
}
-
-func centerLines(s string, width int) string {
- lines := strings.Split(strings.TrimRight(s, "\n"), "\n")
- style := lipgloss.NewStyle().Width(width).Align(lipgloss.Center)
- for i, l := range lines {
- lines[i] = style.Render(l)
- }
- return strings.Join(lines, "\n")
-}
diff --git a/internal/ui/theme.go b/internal/ui/theme.go
index 7faebf5..9d81aab 100644
--- a/internal/ui/theme.go
+++ b/internal/ui/theme.go
@@ -1,6 +1,7 @@
package ui
import (
+ "math/rand"
"strconv"
)
@@ -63,7 +64,7 @@ func RandomTheme() Theme {
}
func randColor() string {
- return strconv.Itoa(rng.Intn(256))
+ return strconv.Itoa(rand.Intn(256))
}
func contrastColor(bg string) string {