From 830384d240c3b7625dd3b20f77d37667793a2e43 Mon Sep 17 00:00:00 2001 From: Ryan Lewis Date: Sat, 10 Oct 2026 16:08:45 +0100 Subject: [PATCH] feat(list): add -f as the short form of --fields --- README.md | 2 +- cmd/things/fields_test.go | 7 +++++++ cmd/things/list.go | 6 +++--- docs/content/commands.md | 4 +++- internal/skill/SKILL.md | 8 ++++---- 5 files changed, 18 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 70a35ed..79b5854 100644 --- a/README.md +++ b/README.md @@ -118,7 +118,7 @@ A JSON listing prints a default set of keys per row, enough to pick an item and act on its `uuid`; notes, the parent uuids and Things' own bookkeeping are left out. `--fields` names the keys you want instead, in that order: `things anytime -j --fields uuid,title,projectTitle,deadline`. -`--fields all` prints every key, as `--json` did by default in v0.10.0 and +`-f` is the short form. `--fields all` prints every key, as `--json` did by default in v0.10.0 and earlier, and `things show -j` prints one item's full record. It works on the task listings, `search` and `projects`, and needs `--json`. An unknown name fails with the list of valid ones. See the diff --git a/cmd/things/fields_test.go b/cmd/things/fields_test.go index 83d1a82..f43e7dd 100644 --- a/cmd/things/fields_test.go +++ b/cmd/things/fields_test.go @@ -54,6 +54,13 @@ func TestRunListingFields(t *testing.T) { "list with filter": {[]string{"-j", "list", "--project", "Chores", "--fields", "title"}, []string{"title"}}, "search": {[]string{"-j", "search", "milk", "--fields", "uuid, title,uuid"}, []string{"uuid", "title"}}, "projects": {[]string{"-j", "projects", "--fields", "openCount,title"}, []string{"openCount", "title"}}, + + "short, bare view": {[]string{"today", "-j", "-f", "uuid,title"}, []string{"uuid", "title"}}, + "short, named view": {[]string{"-j", "anytime", "-f", "uuid,projectTitle"}, []string{"uuid", "projectTitle"}}, + "short, list": {[]string{"list", "anytime", "-a", "Home", "-j", "-f", "uuid"}, []string{"uuid"}}, + "short, search": {[]string{"-j", "search", "milk", "-f", "uuid, title,uuid"}, []string{"uuid", "title"}}, + "short, projects": {[]string{"-j", "projects", "-f", "openCount,title"}, []string{"openCount", "title"}}, + "short, joined value": {[]string{"-j", "projects", "-fopenCount,title"}, []string{"openCount", "title"}}, } for name, c := range cases { t.Run(name, func(t *testing.T) { diff --git a/cmd/things/list.go b/cmd/things/list.go index d00d0fb..6914435 100644 --- a/cmd/things/list.go +++ b/cmd/things/list.go @@ -24,7 +24,7 @@ type ListCmd struct { From string `help:"Only tasks scheduled on or after YYYY-MM-DD (or RFC3339). On 'deadlines', filters by deadline; on 'upcoming', an undated task is matched by its deadline."` To string `help:"Only tasks scheduled on or before YYYY-MM-DD (or RFC3339). On 'deadlines', filters by deadline; on 'upcoming', an undated task is matched by its deadline."` - Fields *string `help:"${fields_help}" placeholder:"KEYS"` + Fields *string `short:"f" help:"${fields_help}" placeholder:"KEYS"` } func (c *ListCmd) Run(kctx *kong.Context, d *Deps) error { @@ -249,7 +249,7 @@ type ProjectsCmd struct { Completed bool `help:"Include completed projects." default:"false"` OpenOnly bool `help:"Leave out the projects closed but not yet logged, which are listed by default as Things still shows them: under the app's default Daily logging, the ones closed today. Ignored with --completed. --open-only=false overrides open_only in the config file."` - Fields *string `help:"${fields_help}" placeholder:"KEYS"` + Fields *string `short:"f" help:"${fields_help}" placeholder:"KEYS"` } func (c *ProjectsCmd) Run(d *Deps) error { @@ -343,7 +343,7 @@ func printItem(d *Deps, database *db.DB, task *model.Task) error { type SearchCmd struct { Query string `arg:"" required:"" help:"Search query."` - Fields *string `help:"${fields_help}" placeholder:"KEYS"` + Fields *string `short:"f" help:"${fields_help}" placeholder:"KEYS"` } func (c *SearchCmd) Run(d *Deps) error { diff --git a/docs/content/commands.md b/docs/content/commands.md index a5539c3..2c22010 100644 --- a/docs/content/commands.md +++ b/docs/content/commands.md @@ -55,11 +55,13 @@ A JSON listing prints a default set of keys for each row: the ones needed to pick an item and act on it. Notes, the parent uuids and Things' own bookkeeping are left out, since notes alone can be half of a full listing. `--fields` names the keys you want instead, in the order you want them, and -`--fields all` prints every key: +`--fields all` prints every key. `-f` is the short form of `--fields` on +the task listings, `search` and `projects`: ```sh things anytime -a "Personal Projects" -j --fields uuid,title,projectTitle,deadline,tags things projects -j --fields uuid,title,openCount +things today -j -f uuid,title things anytime -j --fields all things show -j # one item's full record, notes and checklist included ``` diff --git a/internal/skill/SKILL.md b/internal/skill/SKILL.md index 7282abd..f3d71cd 100644 --- a/internal/skill/SKILL.md +++ b/internal/skill/SKILL.md @@ -48,7 +48,7 @@ Every command that reads or writes Things accepts `--json` / `-j`; `version`, `c - `logbook` is everything closed, not just everything finished: cancelled items sit beside completed ones, as they do in the app's Logbook. Split them on `"status"` — `"completed"` or `"cancelled"`; plain output prints `[x]` and `[~]`. Filter with `jq '.[] | select(.status=="completed")'` when you mean finished rather than closed. - `things projects` also reports `taskCount` and `openCount`. `taskCount` is every untrashed task in the project; `openCount` is the ones still open. The difference is the ones that are no longer open, which means completed or cancelled. Tasks filed under a project heading count towards both; the heading rows themselves never do, and neither do trashed tasks or checklist items. Both numbers are Things' own bookkeeping, read straight from the database rather than recounted by the CLI. - **A `-j` listing prints a default set of keys, not the full record.** Task rows carry `uuid`, `title`, `type`, `status`, `start`, `startBucket`, `startDate`, `reminderTime`, `deadline`, `stopDate`, `projectTitle`, `projectTrashed`, `areaTitle`, `headingTitle`, `tags`, `repeating` and `checklistProgress`; `things projects` rows carry `uuid`, `title`, `status`, `start`, `startDate`, `deadline`, `areaTitle`, `tags`, `taskCount` and `openCount` (each left out when the row has no value, as before). `notes`, the parent uuids (`projectUUID`, `areaUUID`, `headingUUID`), `creationDate`, `index`, `todayIndex`, `trashed`, and `startBucket` on a `things projects` row, are not in a listing unless you ask: read one item's notes with `things show -j`, or pass `--fields all` for every key of every row. **This changed:** before, `-j` printed every key. This applies to the task listings, `search` and `projects`; `show` is always the full record. -- **Pick keys with `--fields`.** `things anytime -a "Area" -j --fields uuid,title,projectTitle,deadline,tags` prints only those keys of each row, in that order; `--fields all` prints the full record and takes no other names. Names are the JSON keys exactly as printed (`projectTitle`, not `project`); a row leaves out a key the full record would leave out. An unknown name, or an empty list, fails before anything is read with `{"error": "unknown field", "kind": "task", "unknown": [...], "valid": [...]}` (no `unknown` for an empty list), so read `valid` and retry. It needs `--json`. +- **Pick keys with `--fields`.** `things anytime -a "Area" -j --fields uuid,title,projectTitle,deadline,tags` prints only those keys of each row, in that order; `--fields all` prints the full record and takes no other names. Names are the JSON keys exactly as printed (`projectTitle`, not `project`); a row leaves out a key the full record would leave out. An unknown name, or an empty list, fails before anything is read with `{"error": "unknown field", "kind": "task", "unknown": [...], "valid": [...]}` (no `unknown` for an empty list), so read `valid` and retry. `-f` is the short form; prefer the long `--fields` in scripts. It needs `--json`. - Human output is styled and column-aligned; colour auto-disables when piping or under `NO_COLOR`. `--color=always|never` overrides. JSON is unaffected. **A failure under `--json` prints one JSON object to stdout and exits non-zero.** Branch on the exit status and read the failure off stdout — not stderr. On success the read commands print their result there. Of the write commands, `add`, `project add`, `edit`, `project edit`, `complete` and `cancel` print the item (rule 3), `tag add` reports what it created and what it skipped, and the rest print nothing. `error` is a stable token; `message` is the human text. @@ -178,7 +178,7 @@ The user may have a TOML file at `~/.config/things-cli/config.toml` (or `$XDG_CO Global flags, valid on every command: `-j/--json`, `--color=auto|always|never`, `--db PATH`, `--config PATH`, `--no-verify`, `--verify-timeout DURATION` (how long a write's read-back waits, default `5s`; must be above zero — use `--no-verify` to skip it), `--no-hints`, `-v/--version`. ``` -things list [view] [--project P] [--area A] [--tag T] [--on D | --from D --to D] [--open-only] [--fields KEYS] +things list [view] [--project P] [--area A] [--tag T] [--on D | --from D --to D] [--open-only] [-f|--fields KEYS] # views: today, inbox, upcoming, anytime, someday, repeating, logbook, trash, deadlines # shortcut: `things today`, `things inbox`, etc. # bare `things` is today — but --project/--area/--tag alone list every open @@ -295,7 +295,7 @@ things list [view] [--project P] [--area A] [--tag T] [--on D | --from D --to D] # page does, and lists that project's row instead. things show [--agent] # detail; --agent prints a Markdown brief (see below) -things projects [-a|--area A] [--completed] [--open-only] [--fields KEYS] +things projects [-a|--area A] [--completed] [--open-only] [-f|--fields KEYS] # open projects plus those closed and not yet logged (as the app's list # still shows them; "status" tells them apart), unless --open-only; # --completed lists every closed project too. @@ -303,7 +303,7 @@ things projects [-a|--area A] [--completed] [--open-only] [--fields KEYS] # plus taskCount/openCount in JSON things areas things tags -things search [--fields KEYS] # titles and notes, matched literally; a lookup, not a view +things search [-f|--fields KEYS] # titles and notes, matched literally; a lookup, not a view # skips trashed rows and tasks of a project in the trash, as the app does things tag add ... # create tags; existing names are skipped