diff --git a/README.md b/README.md index 20637fc..b8ea01b 100644 --- a/README.md +++ b/README.md @@ -567,8 +567,12 @@ reloads it afterwards. In Vim mode, `Ctrl+Z` suspends to the shell. with `:tasks list|kanban|calendar`, `Space x`, `Space k`, or the rows under Tasks in the sidebar; `v` cycles them. `x` toggles, Enter opens the note at the line, `p d w c /` set priority, due date, waiting, cancelled - and in progress, `f` filters, `m` opens the menu. The default board uses - Today / Upcoming / In progress / Waiting / Done. `H`/`L` move a card; + and in progress, `f` filters, `m` opens the menu. The list and the default + board use Today / Upcoming / No due date / In progress / Waiting / Done + (moving a card to No due date clears its due date). `O` or `:order + priority|note` orders the list inside each group by priority or by the + notes' line order (`tasks_list_order`, shared with the desktop's Order + menu; `J`/`K` reorder in note order). `H`/`L` move a card; `g` regroups by status, priority, due date, folder or `field:`. `:boardoptions` (also F2 → Board options) sets the folder root, column labels, custom statuses and card order. Folder boards keep cross-folder moves diff --git a/internal/config/prefs.go b/internal/config/prefs.go index 3c3c8c2..4a08a03 100644 --- a/internal/config/prefs.go +++ b/internal/config/prefs.go @@ -54,6 +54,7 @@ type Prefs struct { CalendarWeekStart string CalendarShowWeekNumbers bool TasksViewMode string + TasksListOrder string // note | priority: the desktop's Order menu above the Tasks list (#989) ShowArchivedTasks bool KanbanGroupBy string KanbanFolderRoot string @@ -114,6 +115,7 @@ func DefaultPrefs() Prefs { CalendarWeekStart: "monday", CalendarShowWeekNumbers: true, TasksViewMode: "list", + TasksListOrder: "note", KanbanGroupBy: "status", KanbanStatuses: []string{}, KanbanColumnTitles: map[string]string{}, @@ -200,6 +202,10 @@ func applyPrefs(p *Prefs, doc map[string]any) { setString(view, "calendar_week_start", &p.CalendarWeekStart) setBool(view, "calendar_show_week_numbers", &p.CalendarShowWeekNumbers) setString(view, "tasks_view_mode", &p.TasksViewMode) + setString(view, "tasks_list_order", &p.TasksListOrder) + if p.TasksListOrder != "priority" { + p.TasksListOrder = "note" + } setBool(view, "show_archived_tasks", &p.ShowArchivedTasks) setString(view, "kanban_group_by", &p.KanbanGroupBy) setString(view, "kanban_folder_root", &p.KanbanFolderRoot) diff --git a/internal/config/prefs_test.go b/internal/config/prefs_test.go index 80d80a2..4bf51e0 100644 --- a/internal/config/prefs_test.go +++ b/internal/config/prefs_test.go @@ -58,3 +58,22 @@ func TestStarterConfigParses(t *testing.T) { t.Fatalf("starter theme: %+v", prefs) } } + +func TestPrefsReadTheTasksListOrder(t *testing.T) { + dir := t.TempDir() + t.Setenv("ZENNOTES_CONFIG_DIR", dir) + prefs, _, err := LoadPrefs() + if err != nil || prefs.TasksListOrder != "note" { + t.Fatalf("default order = %q, %v", prefs.TasksListOrder, err) + } + for _, tc := range []struct{ value, want string }{{"priority", "priority"}, {"note", "note"}, {"due", "note"}} { + toml := "[view]\ntasks_list_order = \"" + tc.value + "\" # note | priority\n" + if err := os.WriteFile(filepath.Join(dir, "config.toml"), []byte(toml), 0o644); err != nil { + t.Fatal(err) + } + prefs, _, err = LoadPrefs() + if err != nil || prefs.TasksListOrder != tc.want { + t.Fatalf("tasks_list_order = %q read as %q, want %q (%v)", tc.value, prefs.TasksListOrder, tc.want, err) + } + } +} diff --git a/internal/tui/commands.go b/internal/tui/commands.go index 9678017..881d17e 100644 --- a/internal/tui/commands.go +++ b/internal/tui/commands.go @@ -55,6 +55,21 @@ func (a *App) commandTable() []command { {names: []string{"comments"}, title: "Note comments", palette: true, run: func(a *App, _ *noteBuffer, _ vim.ExCommand) error { a.openComments(); return nil }}, {names: []string{"filters"}, title: "Saved task filters", palette: true, run: func(a *App, _ *noteBuffer, _ vim.ExCommand) error { a.savedTaskFilters(); return nil }}, {names: []string{"savefilter"}, title: "Save current task filter", palette: true, run: func(a *App, _ *noteBuffer, _ vim.ExCommand) error { a.saveTaskFilter(); return nil }}, + {names: []string{"order"}, title: "Order the task list (note | priority)", palette: true, run: func(a *App, _ *noteBuffer, cmd vim.ExCommand) error { + switch want := strings.ToLower(strings.TrimSpace(cmd.Args)); want { + case "note", "priority": + a.setTasksListOrder(want) + case "": + next := "priority" + if a.prefs.TasksListOrder == "priority" { + next = "note" + } + a.setTasksListOrder(next) + default: + a.notify("Usage: :order note | priority") + } + return nil + }}, {names: []string{"boardoptions"}, title: "Task board options", palette: true, run: func(a *App, _ *noteBuffer, _ vim.ExCommand) error { if v := a.activeTasksView(); v != nil { v.boardMenu(a) diff --git a/internal/tui/helpdata.go b/internal/tui/helpdata.go index b62da95..bcaadc8 100644 --- a/internal/tui/helpdata.go +++ b/internal/tui/helpdata.go @@ -189,13 +189,14 @@ func helpLines(a *App, filter string) []string { "x / Enter\tToggle done; open the task's note at its line", "p d w c /\tPriority, due date, waiting, cancelled, in progress", "e s < >\tEdit text, set a field, shift the due date by a day", - "J K\tMove the task up or down inside its note", + "J K\tMove the task up or down inside its note (list in note order)", + "O / :order\tList order: note order or priority (high first in each group); shared with the desktop's Order menu via tasks_list_order", "n f F A\tNew task in the daily note, filter, clear the filter, include archived", "m\tTask menu (includes forward to today's daily note)", "Board: h l j k\tMove between columns and cards; H L move the card; g cycles the grouping", "Calendar: h j k l [ ] t\tMove days and months, t is today; Enter lists the day's tasks; o opens the daily note", "Filter syntax\tDesktop substring matching: task/note text, !high, #tag, @field:value. Terminal operators require where:, e.g. where: is:open due:today -meeting", - "Board status\tToday / Upcoming / In progress / Waiting / Done; custom status uses field:status. Folder boards do not move cards between folders.", + "Board status\tToday / Upcoming / No due date / In progress / Waiting / Done; custom status uses field:status. Folder boards do not move cards between folders.", "F2 / :boardoptions\tView actions, saved filters, grouping, folder root, labels and persistent card order", "", "## Tags", diff --git a/internal/tui/task_filters.go b/internal/tui/task_filters.go index b54a27c..f10d852 100644 --- a/internal/tui/task_filters.go +++ b/internal/tui/task_filters.go @@ -124,8 +124,39 @@ func (a *App) filterMenu(name string) { }}, }) } + +// setTasksListOrder writes tasks_list_order to config.toml, the key the +// desktop's Order menu above the Tasks list uses (#989), so both agree. +func (a *App) setTasksListOrder(order string) { + if err := config.SetValue("view", "tasks_list_order", order); err != nil { + a.notifyError(err.Error()) + return + } + _ = a.reloadPreferences() + a.prefs.TasksListOrder = order + if v := a.activeTasksView(); v != nil { + v.refresh(a) + } + if order == "priority" { + a.notify("Tasks ordered by priority") + } else { + a.notify("Tasks in their notes' order") + } +} + func (v *tasksView) boardMenu(a *App) { + listOrder := "List order: priority (O switches to note order)" + if a.prefs.TasksListOrder != "priority" { + listOrder = "List order: note order (O switches to priority)" + } a.showMenu("Board options", []menuItem{ + {key: "o", label: listOrder, run: func(a *App) { + next := "priority" + if a.prefs.TasksListOrder == "priority" { + next = "note" + } + a.setTasksListOrder(next) + }}, {key: "g", label: "Group by", run: func(a *App) { items := []paletteItem{} for _, g := range v.groupOptions() { diff --git a/internal/tui/task_query_test.go b/internal/tui/task_query_test.go index 572ea6d..86f0d0a 100644 --- a/internal/tui/task_query_test.go +++ b/internal/tui/task_query_test.go @@ -74,7 +74,7 @@ func TestTaskViewsApplyPortableSavedQuery(t *testing.T) { v := &tasksView{groupBy: "status", filter: "@project:alpha"} v.refresh(a) assertTaskQueryIDs(t, v.tasks, []string{"alpha"}) - assertKanbanCards(t, v, "today", []string{"alpha"}) + assertKanbanCards(t, v, "undated", []string{"alpha"}) } func assertTaskQueryIDs(t *testing.T, tasks []vault.Task, want []string) { diff --git a/internal/tui/tasks_list_order_test.go b/internal/tui/tasks_list_order_test.go new file mode 100644 index 0000000..1e20d0c --- /dev/null +++ b/internal/tui/tasks_list_order_test.go @@ -0,0 +1,44 @@ +package tui + +import ( + "testing" + "time" + + "github.com/ZenNotes/tui/internal/config" + "github.com/ZenNotes/tui/internal/vault" +) + +// The list follows tasks_list_order, the desktop's Order menu (#989). +func TestTasksListFollowsTheListOrder(t *testing.T) { + today := vault.TodayISO(time.Now()) + tasks := []vault.Task{ + {ID: "bank", Content: "bank", SourcePath: "a.md", TaskIndex: 0, Priority: "med", Due: today}, + {ID: "passport", Content: "passport", SourcePath: "a.md", TaskIndex: 1, Priority: "high", Due: today}, + {ID: "plants", Content: "plants", SourcePath: "b.md", TaskIndex: 0, Due: today}, + } + for _, tc := range []struct { + order string + want []string + }{ + {"note", []string{"bank", "passport", "plants"}}, + {"priority", []string{"passport", "bank", "plants"}}, + } { + a := &App{idx: &index{tasks: tasks}, prefs: prefsView{Prefs: config.Prefs{TasksListOrder: tc.order}}} + v := &tasksView{mode: "list"} + v.refresh(a) + var got []string + for _, row := range v.rows { + if row.task != nil { + got = append(got, row.task.ID) + } + } + if len(got) != len(tc.want) { + t.Fatalf("%s: rows = %v, want %v", tc.order, got, tc.want) + } + for i := range got { + if got[i] != tc.want[i] { + t.Fatalf("%s: rows = %v, want %v", tc.order, got, tc.want) + } + } + } +} diff --git a/internal/tui/tasks_parity_test.go b/internal/tui/tasks_parity_test.go index a9353c7..ff3daa4 100644 --- a/internal/tui/tasks_parity_test.go +++ b/internal/tui/tasks_parity_test.go @@ -36,18 +36,18 @@ func TestKanbanStatusColumnsMatchDesktop(t *testing.T) { }} a := &App{prefs: prefsView{Prefs: config.Prefs{KanbanStatuses: []string{"review", "blocked"}}}} v.buildColumns(a) - assertKanbanColumnIDs(t, v, []string{"today", "upcoming", "in-progress", "waiting", "done"}) - wantTitles := []string{"Today", "Upcoming", "In progress", "Waiting", "Done"} + assertKanbanColumnIDs(t, v, []string{"today", "upcoming", "undated", "in-progress", "waiting", "done"}) + wantTitles := []string{"Today", "Upcoming", "No due date", "In progress", "Waiting", "Done"} for i, col := range v.columns { if col.title != wantTitles[i] { t.Errorf("column %q title = %q, want %q", col.id, col.title, wantTitles[i]) } } want := map[string]string{ - "undated": "today", "due-today": "today", "overdue": "today", + "undated": "undated", "due-today": "today", "overdue": "today", "future": "upcoming", "started-undated": "in-progress", "started-future": "in-progress", "waiting-started": "waiting", "waiting-overdue": "waiting", "done-waiting": "done", - "custom-status": "today", "custom-started": "today", + "custom-status": "undated", "custom-started": "undated", } got := map[string]string{} for _, col := range v.columns { @@ -211,6 +211,7 @@ func TestKanbanStatusMovesMatchDesktopMutations(t *testing.T) { {name: "progress clears waiting and preserves due", line: "- [ ] Work @waiting due:" + future, target: "in-progress", due: future, progress: true}, {name: "waiting preserves progress and due", line: "- [/] Work due:" + future, target: "waiting", due: future, waiting: true, progress: true}, {name: "done preserves waiting and due", line: "- [/] Work @waiting due:" + future, target: "done", due: future, waiting: true, checked: true}, + {name: "no due date clears due and reopens (#990)", line: "- [/] Work @waiting due:" + future, target: "undated", due: ""}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -229,6 +230,24 @@ func TestKanbanStatusMovesMatchDesktopMutations(t *testing.T) { } } +func TestKanbanNoDueDateRefusesADailyNoteDate(t *testing.T) { + // The date comes from the note, not a due: on the line, so there is nothing + // to clear and the card would land straight back in its day (#990). + const body = "- [ ] Work @status:review\n" + a, path, task := newKanbanMutationTestApp(t, body) + task.Due = vault.TodayISO(time.Now()) + task.DueInferred = true + v := &tasksView{groupBy: "status", columns: []kanbanColumn{{id: "undated"}}} + v.moveCard(a, task, 0) + got, err := os.ReadFile(path) + if err != nil { + t.Fatal(err) + } + if string(got) != body { + t.Errorf("a daily-note task must not be rewritten; body=%q, want %q", got, body) + } +} + func TestKanbanFieldMovesWriteUnprefixedField(t *testing.T) { tests := []struct{ group, target, key, want string }{ {"field:project", "beta", "project", "beta"}, diff --git a/internal/tui/views_tasks.go b/internal/tui/views_tasks.go index 0c11ff5..b5fd016 100644 --- a/internal/tui/views_tasks.go +++ b/internal/tui/views_tasks.go @@ -88,7 +88,7 @@ func (v *tasksView) setMode(mode string) { func (v *tasksView) refresh(a *App) { all := a.displayTasks() v.tasks = filterTaskQuery(all, v.filter) - groups := vault.GroupTasks(v.tasks, time.Now()) + groups := vault.OrderTaskGroups(vault.GroupTasks(v.tasks, time.Now()), a.prefs.TasksListOrder) v.rows = nil add := func(name string, tasks []vault.Task, extra string) { if len(tasks) == 0 { @@ -110,6 +110,7 @@ func (v *tasksView) refresh(a *App) { } add("Today", groups.Today, overdue) add("Upcoming", groups.Upcoming, "") + add("No due date", groups.Undated, "") add("Waiting", groups.Waiting, "") add("Done", groups.Done, "") add("Forwarded", groups.Forwarded, "") @@ -290,7 +291,7 @@ func (v *tasksView) buildColumns(a *App) { } } case "status", "": - for _, c := range []struct{ id, title string }{{"today", "Today"}, {"upcoming", "Upcoming"}, {"in-progress", "In progress"}, {"waiting", "Waiting"}, {"done", "Done"}} { + for _, c := range []struct{ id, title string }{{"today", "Today"}, {"upcoming", "Upcoming"}, {"undated", "No due date"}, {"in-progress", "In progress"}, {"waiting", "Waiting"}, {"done", "Done"}} { cols = append(cols, kanbanColumn{id: c.id, title: v.columnTitle(a, c.id, c.title)}) } today := vault.TodayISO(time.Now()) @@ -306,6 +307,8 @@ func (v *tasksView) buildColumns(a *App) { id = "waiting" case t.InProgress: id = "in-progress" + case t.Due == "": + id = "undated" case t.Due > today: id = "upcoming" } @@ -772,6 +775,14 @@ func (v *tasksView) handleKey(a *App, k vim.Key) bool { v.boardMenu(a) return true } + if k.IsRune('O') && v.mode == "list" && a.listKeyAllowed(k) { + next := "priority" + if a.prefs.TasksListOrder == "priority" { + next = "note" + } + a.setTasksListOrder(next) + return true + } if k.IsRune('v') && a.listKeyAllowed(k) { switch v.mode { case "list": @@ -893,13 +904,18 @@ func (v *tasksView) listKey(a *App, k vim.Key) bool { if t != nil { a.openTaskSource(*t) } - case "tasks.moveTaskUp": - if t != nil { - a.moveTaskWithinNote(*t, -1) + case "tasks.moveTaskUp", "tasks.moveTaskDown": + // J and K move lines in the note, which the list only shows in note order. + if a.prefs.TasksListOrder == "priority" { + a.notify("Reordering works in note order. Press O to switch.") + return true } - case "tasks.moveTaskDown": if t != nil { - a.moveTaskWithinNote(*t, 1) + dir := 1 + if id == "tasks.moveTaskUp" { + dir = -1 + } + a.moveTaskWithinNote(*t, dir) } case "nav.localEx": a.openLocalEx() @@ -1043,6 +1059,10 @@ func (v *tasksView) moveCard(a *App, t vault.Task, target int) { return } case "status", "": + if col.id == "undated" && t.DueInferred { + a.notify("This task's date comes from its daily note, so there is no due date to clear") + return + } a.setTaskStatusColumn(t, col.id) case "folder": a.notify("Folder boards are read-only. Move the source note to change its folder.") @@ -1305,6 +1325,11 @@ func (a *App) setTaskStatusColumn(t vault.Task, status string) { checked(false) waiting(false) progress(true) + case "undated": + checked(false) + waiting(false) + progress(false) + due("") case "today", "upcoming": checked(false) waiting(false) diff --git a/internal/vault/tasks.go b/internal/vault/tasks.go index b011cdc..e1cc26f 100644 --- a/internal/vault/tasks.go +++ b/internal/vault/tasks.go @@ -1034,7 +1034,9 @@ func ComposeTaskFile(in ComposeTaskFileInput) string { } // GroupTasks buckets tasks for the list view. Waiting overrides everything -// but Done; tasks without a due date land in Today. +// but Done. Tasks without a due date have their own group, as in the desktop +// app since ZenNotes 2.76 (#990): they used to land in Today. A daily-note task +// is dated by InferDailyTaskDueDates before it gets here, so it stays in Today. func GroupTasks(tasks []Task, today time.Time) TaskGroups { todayISO := TodayISO(today) g := TaskGroups{} @@ -1049,7 +1051,7 @@ func GroupTasks(tasks []Task, today time.Time) TaskGroups { case task.Waiting: g.Waiting = append(g.Waiting, task) case task.Due == "": - g.Today = append(g.Today, task) + g.Undated = append(g.Undated, task) case task.Due < todayISO: g.Today = append(g.Today, task) g.OverdueCount++ @@ -1090,6 +1092,7 @@ func GroupTasks(tasks []Task, today time.Time) TaskGroups { } sortTasks(g.Today, byPriorityThenDue) sortTasks(g.Upcoming, byDueThenPath) + sortTasks(g.Undated, byPriorityThenDue) sortTasks(g.Waiting, byPriorityThenDue) sortTasks(g.Done, byPath) sortTasks(g.Forwarded, byDueThenPath) @@ -1097,6 +1100,51 @@ func GroupTasks(tasks []Task, today time.Time) TaskGroups { return g } +// OrderTaskGroups orders each Tasks list group the way the desktop's Order +// menu says (#989): "note" keeps every group in its notes' line order, which +// J and K rearrange; "priority" puts high before medium before low before +// none in the live groups, ties by due date and then line order, and leaves +// forwarded, done and cancelled in line order. +func OrderTaskGroups(g TaskGroups, order string) TaskGroups { + byLine := func(a, b Task) bool { + if a.SourcePath != b.SourcePath { + return a.SourcePath < b.SourcePath + } + return a.TaskIndex < b.TaskIndex + } + rank := map[string]int{"high": 0, "med": 1, "low": 2, "": 3} + byPriority := func(a, b Task) bool { + if rank[a.Priority] != rank[b.Priority] { + return rank[a.Priority] < rank[b.Priority] + } + ad, bd := a.Due, b.Due + if ad == "" { + ad = "9999-99-99" + } + if bd == "" { + bd = "9999-99-99" + } + if ad != bd { + return ad < bd + } + return byLine(a, b) + } + live := byLine + if order == "priority" { + live = byPriority + } + out := g + for _, group := range []*[]Task{&out.Today, &out.Upcoming, &out.Undated, &out.Waiting} { + *group = append([]Task(nil), (*group)...) + sortTasks(*group, live) + } + for _, group := range []*[]Task{&out.Done, &out.Forwarded, &out.Cancelled} { + *group = append([]Task(nil), (*group)...) + sortTasks(*group, byLine) + } + return out +} + func sortTasks(tasks []Task, less func(a, b Task) bool) { sort.SliceStable(tasks, func(i, j int) bool { return less(tasks[i], tasks[j]) }) } diff --git a/internal/vault/types.go b/internal/vault/types.go index 5412208..8da1742 100644 --- a/internal/vault/types.go +++ b/internal/vault/types.go @@ -137,11 +137,12 @@ type Task struct { DueInferred bool `json:"dueInferred,omitempty"` } -// TaskGroups is the Tasks list's bucketing: Today (undated, due today, and -// overdue), Upcoming, Waiting, Done, Forwarded, Cancelled. +// TaskGroups is the Tasks list's bucketing: Today (due today and overdue), +// Upcoming, Undated (no due date), Waiting, Done, Forwarded, Cancelled. type TaskGroups struct { Today []Task Upcoming []Task + Undated []Task Waiting []Task Done []Task Forwarded []Task diff --git a/internal/vault/vault_test.go b/internal/vault/vault_test.go index 3e9f761..4ab6b01 100644 --- a/internal/vault/vault_test.go +++ b/internal/vault/vault_test.go @@ -388,7 +388,8 @@ func TestGroupTasks(t *testing.T) { {ID: "a#7", Due: "2026-09-08", Priority: "high"}, } g := GroupTasks(tasks, today) - if len(g.Today) != 3 || g.OverdueCount != 1 || len(g.Upcoming) != 1 || len(g.Waiting) != 1 || len(g.Done) != 1 || len(g.Forwarded) != 1 || len(g.Cancelled) != 1 { + // An undated task has its own group (#990), out of Today. + if len(g.Today) != 2 || g.OverdueCount != 1 || len(g.Upcoming) != 1 || len(g.Undated) != 1 || g.Undated[0].ID != "a#1" || len(g.Waiting) != 1 || len(g.Done) != 1 || len(g.Forwarded) != 1 || len(g.Cancelled) != 1 { t.Fatalf("groups = %+v", g) } if g.Today[0].ID != "a#7" { @@ -396,6 +397,40 @@ func TestGroupTasks(t *testing.T) { } } +func TestOrderTaskGroups(t *testing.T) { + // The desktop's Order menu above the Tasks list (#989). + g := TaskGroups{ + Today: []Task{ + {ID: "bank", SourcePath: "a.md", TaskIndex: 0, Priority: "med", Due: "2026-10-23"}, + {ID: "passport", SourcePath: "a.md", TaskIndex: 1, Priority: "high", Due: "2026-10-20"}, + {ID: "plants", SourcePath: "b.md", TaskIndex: 0, Due: "2026-10-23"}, + {ID: "invoice", SourcePath: "b.md", TaskIndex: 1, Priority: "low", Due: "2026-10-23"}, + {ID: "contract", SourcePath: "c.md", TaskIndex: 0, Priority: "high", Due: "2026-10-23"}, + }, + Done: []Task{{ID: "b-done", SourcePath: "b.md", Priority: "low"}, {ID: "a-done", SourcePath: "a.md", Priority: "high"}}, + } + ids := func(tasks []Task) string { + out := []string{} + for _, t := range tasks { + out = append(out, t.ID) + } + return strings.Join(out, ",") + } + if got := ids(OrderTaskGroups(g, "note").Today); got != "bank,passport,plants,invoice,contract" { + t.Fatalf("note order = %s", got) + } + byPriority := OrderTaskGroups(g, "priority") + if got := ids(byPriority.Today); got != "passport,contract,bank,invoice,plants" { + t.Fatalf("priority order = %s", got) + } + if got := ids(byPriority.Done); got != "a-done,b-done" { + t.Fatalf("done keeps line order: %s", got) + } + if ids(g.Today) != "bank,passport,plants,invoice,contract" { + t.Fatalf("OrderTaskGroups must not reorder its input: %s", ids(g.Today)) + } +} + func TestUpdateFrontmatterFieldsQuoting(t *testing.T) { got := UpdateFrontmatterFields("body\n", []FrontmatterUpdate{{Key: "Link", Value: StrPtr("[[Note]]")}, {Key: "Plain", Value: StrPtr("hello world")}}) if got != "---\nLink: \"[[Note]]\"\nPlain: hello world\n---\nbody\n" { diff --git a/packaging/homebrew/Formula/zn.rb b/packaging/homebrew/Formula/zn.rb index b46f723..7fc8d5a 100644 --- a/packaging/homebrew/Formula/zn.rb +++ b/packaging/homebrew/Formula/zn.rb @@ -5,23 +5,23 @@ class Zn < Formula on_macos do on_arm do - url "https://github.com/ZenNotes/tui/releases/download/v0.9.2/zn_0.9.2_darwin_arm64.tar.gz" - sha256 "0eb85dc50c28855d0929b54928a86797dc1aa545901340ce7052468840d35d2c" + url "https://github.com/ZenNotes/tui/releases/download/v0.11.0/zn_0.11.0_darwin_arm64.tar.gz" + sha256 "4b3548577ece83dc311bb67d72d4389a0a48a24c3bd56b9ba28aaa705303d33f" end on_intel do - url "https://github.com/ZenNotes/tui/releases/download/v0.9.2/zn_0.9.2_darwin_amd64.tar.gz" - sha256 "d6cf4e7007dbb94ec720605dbe3369e20b006226a3ccbe22aa9a85e669493d68" + url "https://github.com/ZenNotes/tui/releases/download/v0.11.0/zn_0.11.0_darwin_amd64.tar.gz" + sha256 "9dd6b9e19c3448ff947c7dd20eec511a6ffb4975616f0a78014c0e6b33047ddb" end end on_linux do on_arm do - url "https://github.com/ZenNotes/tui/releases/download/v0.9.2/zn_0.9.2_linux_arm64.tar.gz" - sha256 "bb0c21763fe0a5a292fbe4d5a3e905aa17fea5ed7c1c65b5c9a019358a41cbf1" + url "https://github.com/ZenNotes/tui/releases/download/v0.11.0/zn_0.11.0_linux_arm64.tar.gz" + sha256 "132eb7755693cea9911783c2097b6a18964e18658a95d99d93353bc1e56ee6e8" end on_intel do - url "https://github.com/ZenNotes/tui/releases/download/v0.9.2/zn_0.9.2_linux_amd64.tar.gz" - sha256 "57f0e231f29df65ac4c06e0052e80dbc36f1459a1844af25256cb6e869990b2c" + url "https://github.com/ZenNotes/tui/releases/download/v0.11.0/zn_0.11.0_linux_amd64.tar.gz" + sha256 "44fd68b60dd82946a210dc715bea4d8d28363870ef7fcc335522e0a3e586d2bd" end end