Tutorial
Accept commands
Read arguments, filter tasks, and explain how to use the tool.
Start with chapter 3's task structs and formatting function. The next version will show open tasks by default, include completed tasks with list --all, and explain itself with --help.
Read the arguments
Add this import at the top of tasks.tea:
use args from "std.args"use imports a module under a local name. std.args is part of Tea's standard library; you don't need to install a package. Call its functions through the alias, such as args.all().
Move the program's executable statements into def run() -> Void ... end and call run() at the bottom of the file. Void means the function doesn't return a useful value. Keep the struct and format_task above it.
At the beginning of run, read the arguments and supply a default command:
var argv = args.all()
if @len(argv) == 0
argv = ["list"]
endRunning tea tasks.tea list --all gives this program ["list", "--all"]. The program name isn't included. Checking the length before using an index avoids reading a missing element.
Separate selecting from displaying
Add the show_tasks function from the complete checkpoint below after format_task. Move the sample list into the list branch of run.
The display function takes a List[Task] and a Bool. Its condition is show_all || !task.done: show a task if all tasks were requested, or if this task is not done. || means “or” and ! negates a boolean.
Increment the task number on every iteration, including tasks you hide. That makes a displayed number keep referring to the same task when the view changes. The separate shown counter lets us distinguish an empty view from an empty collection.
Validate the command
The complete run function handles --help and list. It rejects extra or unrecognized arguments, rather than quietly ignoring them. && means “and”; conditions joined by && and || short-circuit, so a length check can guard access to argv[1].
The help function writes usage to standard output. The usage function writes an error to standard error with @eprintln, then calls @exit(2). We'll reserve status 2 for usage errors and 1 for data or file failures. Finishing normally means success, status 0.
Run both views
tea tasks.tea list1. [ ] Learn Tea
2. [ ] Build a CLItea tasks.tea list --all1. [ ] Learn Tea
2. [ ] Build a CLI
3. [x] Take a breakRunning tea tasks.tea gives the first view too. Try tea tasks.tea -- --help to see the supported command shapes. The first -- separates Tea's own options from your script's arguments; it is not included in args.all(). Use it when the first argument for your script starts with a hyphen. tea tasks.tea list --unknown reports an error rather than running a different command.
Script exit status
The current Tea launcher reports a failed script as status 1 and adds a
“program exited with status” message, even when the script calls
@exit(2). The native executable you'll build in chapter 9
preserves the program's status codes.
Complete checkpoint
Complete tasks.tea for this chapter
tasks.tea
use args from "std.args"
struct Task {
title: String
done: Bool
}
def format_task(task: Task, number: Int) -> String
const marker = if(task.done) "[x]" else "[ ]"
`${number}. ${marker} ${task.title}`
end
def show_tasks(tasks: List[Task], show_all: Bool) -> Void
if @len(tasks) == 0
@println("No tasks yet.")
return
end
var number = 1
var shown = 0
for task in tasks
if show_all ||!task.done
@println(format_task(task, number))
shown = shown + 1
end
number = number + 1
end
if shown == 0
@println("No open tasks.")
end
end
def help() -> Void
@println("Usage: tasks [list [--all] | --help]")
@println("Tasks are numbered from 1. Listing shows open tasks; --all includes completed tasks.")
end
def usage() -> Void
@eprintln("tasks: invalid arguments; run tasks --help for usage")
@exit(2)
end
def run() -> Void
var argv = args.all()
if @len(argv) == 0
argv = ["list"]
end
if argv[0] == "--help" && @len(argv) == 1
help()
return
end
if argv[0] == "list"
if @len(argv) > 2 ||(@len(argv) == 2 && argv[1] != "--all")
usage()
return
end
const tasks = [
Task(title: "Learn Tea", done: false),
Task(title: "Build a CLI", done: false),
Task(title: "Take a break", done: true)
]
show_tasks(tasks, @len(argv) == 2)
return
end
usage()
end
run()Try it yourself
Add a count command that prints the number of sample tasks. Keep it separate from the display function.
Hint
Check the first argument and the total argument count before running the command. Reuse @len(tasks) from chapter 2. For this exercise you can move the sample list above the command branches; the main walkthrough keeps it in the list branch until the next chapter replaces it with file loading.
You now have a small command-line interface. The sample data still resets each time the program runs; next we'll load it from a file.
Read more: command-line argument helpers, imports.