std.cli.interactive
A program’s commands, as std.cli says them, learned by using them: a
list of the commands with what each does, filtered by what is typed;
a command picked is a form of its positionals and its flags — each
with what it is, its values, whether it is wanted — and the command
line the form makes, shown as it is filled in, with what is wrong with
it yet. Done, it is the words of that command line, for the program
to run as if they had been given it (CLI.readLine). An app of
std.terminal.widget’s, pure: std.terminal runs it on the terminal
(Terminal.interact (Interactive.app "heff" (Interactive.entries cs))); heff with no words runs heff’s own. A command line that
lacks only what its command wants (heff run, no file) opens on the
command’s form alone, filled in with what it has (lacking,
prompt). Import it by a name, import std.cli.interactive as Interactive.
Keys: on the list, up and down (or j and k, Ctrl-N and Ctrl-P) to
move, a page, Home and End; anything typed filters it by the
commands’ names (/ first to type a j, k or q); Enter or Tab
opens the command; Esc clears the filter, or ends, as q does. On a
form, Tab and down to the next field, Shift-Tab and up to the one
before; a field of words is typed in as a shell’s line is — in a
field of paths, the names its last word completes to shown under it,
and Tab completing it as far as they all go (listed lists them) —
a choice turned by left and right (or space); Enter ends, with the command
line, once nothing is wrong with it; Esc goes back to the list (and
q, on a choice), or, on a form alone, ends.
Entry
type Entry = { name : String, doc : String, shape : CLI.Shape }A command, as the list and its form show it: its name, what it does, and the words it takes.
entries
entries : {r : Type} -> List (CLI.Command r) -> List EntryThe commands the usage shows, as entries.
Part
data Part = Positional CLI.Pos | Flagged CLI.FlagWhat a field of a form is for: a positional, or a flag.
Input
data Input = Typed Widget.Field | Picked Widget.ChoiceWhat a field holds: words typed, or a value chosen.
Slot
type Slot = { part : Part, input : Input }A field of a form.
Form
type Form = { entry : Entry, slots : List Slot, at : Int }A command’s form: the command, its fields — its positionals, then its flags — and the one being filled in.
formOf
formOf : Entry -> FormThe command’s form, empty.
formWords
formWords : Form -> List StringThe words of the command line the form makes, after the command’s name.
formProblem
formProblem : Form -> Maybe CLI.ProblemWhat is wrong with the command line the form makes, if anything.
lacking
lacking : List Entry -> List String -> Maybe FormThe form of the command the words call, filled in with them, where
all that is wrong with them is a positional or a flag wanted
(Missing, MissingFlag): the first field still wanted is the one
being filled in.
>>> maybe Nil formWords (lacking (entries CLI.commandsEx) ["compile", "a.hf", "-bc"])["a.hf", "--backend=c"]>>> maybe (0 - 1) (\(fm : Form) -> fm.at) (lacking (entries CLI.commandsEx) ["compile", "a.hf", "-bc"])1>>> maybe (0 - 1) (\(fm : Form) -> fm.at) (lacking (entries CLI.commandsEx) ["compile", "a.hf", "a.mjs"])3>>> maybe (0 - 1) (\(fm : Form) -> fm.at) (lacking (entries CLI.commandsEx) ["compile", "a.hf", "a.mjs", "b", "-bc"])-1>>> maybe (0 - 1) (\(fm : Form) -> fm.at) (lacking (entries CLI.commandsEx) ["compile", "a.hf", "-b", "wasm"])-1>>> maybe (0 - 1) (\(fm : Form) -> fm.at) (lacking (entries CLI.commandsEx) ["compile", "-h"])-1>>> maybe (0 - 1) (\(fm : Form) -> fm.at) (lacking (entries CLI.commandsEx) ["run"])0quoted
quoted : String -> StringA word as a shell is to be given it: as it is, or in single quotes.
>>> List.map quoted ["a.hf", "two words", "it's", ""]["a.hf", "'two words'", "'it'\\''s'", "''"]commandLine
commandLine : String -> String -> List String -> StringThe command line: the program, the command, its words, as a shell is to be given them.
Listing
type Listing = { dir : String, names : List String }A directory, as a path typed in a field is completed in it: the
directory as typed ("", the working one), and each name in it, a
directory’s with a / after it.
pathsFor
pathsFor : CLI.Complete -> Listing -> String -> List StringWhat a path being typed completes to, of the kind: the names listed
in its directory that start as the rest of it does and that the kind
takes — one that starts with . only where the rest does.
>>> pathsFor (Files ".hf") { dir = "src/", names = ["a.hf", "ab/", "b.hf", "c.txt", ".x/"] } "src/a"["src/a.hf", "src/ab/"]>>> pathsFor Dirs { dir = "", names = ["a.hf", "ab/", ".x/"] } ""["ab/"]>>> pathsFor Dirs { dir = "", names = ["ab/", ".x/"] } "."[".x/"]>>> pathsFor (Files ".hf") { dir = "", names = ["a.hf"] } "src/"[]Model
type Model = { prog : String , entries : List Entry , filter : Widget.Field , typing : Bool , menu : Widget.Menu , form : Maybe Form , alone : Bool , listing : Maybe Listing }Where the app is: the program’s name, its commands, the filter
typed and whether it is being typed (j, k and q are then
letters of it), which of the commands it lets through is picked,
the form open, if one is, whether the form is all there is (no
list to go back to: prompt), and the directory listed for the
path being typed in it, if one is (listed).
start
start : String -> List Entry -> ModelThe list of the commands, nothing typed.
matching
matching : Model -> List EntryThe commands the filter lets through: those whose names have it.
picked
picked : Model -> Maybe EntryThe command picked, if the filter lets any through.
Result
type Result = Maybe (List String)step
step : Widget.Key -> Model -> Widget.Step Model ResultWhat a key makes of the app: on the list, or on the form open.
view
view : Widget.Size -> Model -> Widget.FrameHow the app is shown on a terminal of the size: the list, or the form open.
app
app : String -> List Entry -> Widget.App Model ResultThe app: the commands of the program prog, to pick one of and fill
in; what it comes to is the words of the command line made (the
command’s name first), or nothing, where it was left.
prompt
prompt : String -> List Entry -> Form -> Widget.App Model ResultThe app opened on the form, for what a command line lacks: as the
app, but where it would go back to the list (Esc, q on a choice)
it ends, with nothing.
listed
listed : {e : HFunctor} -> {{disk : filesystem <: e}} -> Model -> Co e ModelThe app’s state with the directory listed that the path being typed
in the form’s field is in (what Tab completes it to, and what is
shown under it), where it is not yet: for Terminal.interactWith
to give each state the app comes to.