Ascii.Pieces.FileTree (Ascii v0.3.0)

Copy Markdown View Source

A tree listing opened folder by folder, then closed again.

A project listed the way tree -F prints it. As upstream draws it, a cursor walks down the list opening one folder at a time, then closes them from the bottom up. With walk: false it is a tree to use instead: your files, the folders you open, and a cursor that keys and clicks move, in a terminal UI or a LiveView.

Options

Give them to Ascii.new/2 as options:, and new ones while it plays with Ascii.put_options/2 (or a Phoenix player's options): the tree is laid out anew from them.

  • root - the first line, above the listing. Default ".".
  • entries - the listing as text: one entry a line, two spaces of indent a level, folders ending in "/". Default: upstream's small web project. Being text, it is cut at 256 characters: for a real tree, give paths.
  • paths - the entries as a list of paths, as Path.wildcard/1 gives them, in place of entries: each path's folders are made from it, a path ending in "/" is a folder, and every folder's entries come in the order first given (sort them for tree's order). Up to 256 paths. Default [], for entries. entries/1 gives the text for paths.
  • walk - true (the default) plays upstream's walk; false draws the tree still, as open and cursor say, and takes keys and clicks.
  • open - with walk: false, the paths of the open folders, as ["src/", "src/lib/"]. An entry's path is its name after its folders', "src/lib/fetch.ts", a folder's ending in "/". Default []: only the root's entries show.
  • cursor - with walk: false, the path of the entry under the cursor, drawn as the walk draws it, the branch turned arrow. One inside a closed folder sits on the nearest folder shown; "" (the default), or a path not in the tree, is no cursor. A listing longer than its rows scrolls to keep the cursor in the middle of them.
  • cols, rows - the frame's size, 12 to 200 by 4 to 100; 36 by 23 by default. The listing is centred in the width, between the root and a blank row over the count.

Colours

In one ink, or a gradient, with :ink and :gradient (see Ascii.Ink); part by part with :parts (see Ascii.Parts), parts: true taking the colours suggested here:

  • root - the first line.
  • branch - the tree's lines, grey.
  • cursor - the branch turned arrow, yellow.
  • folder - a folder's name, blue.
  • file, and file.<extension> - a file's name, and by its extension in lowercase (file.ts for index.ts; a name without one, or a dotfile, is just file). Suggested: file.ex and file.exs purple, file.ts blue, file.js and file.json yellow, file.css pink, file.md grey; any other in the ink. %{"file.rs" => "#dea584"} colours a kind of your own.
  • marker - the + on a closed folder, yellow.
  • summary - the count on the last row, grey.

Keys and clicks

With walk: false, Ascii.handle_event/2 takes keys and clicks, changing cursor and open, from which the app reads the choice:

  • ↑ and ↓ move the cursor, as do home, end, page up and page down; with no cursor, any of them puts it on the first entry (end, the last).
  • → or enter opens a closed folder, and → on an open one moves into it; ← closes an open folder, or moves to the folder an entry is in; enter and space open and close a folder.
  • A click on an entry's row puts the cursor on it, and opens or closes it if it is a folder.
  • Enter on a file is ignored, as is a key that would change nothing: the app has the key, and the file in cursor.

Walking, it takes none. In Phoenix, give the player interactive (and notify to be told of each key and click); in ExRatatui, Ascii.ExRatatui.handle_event/3; in a terminal, mix ascii.play file-tree --option walk=false --interactive.

Screen readers

Ascii.describe/1 tells the tree and where the cursor is, as "file tree of my_app: 2 folders, 4 files; at lib/my_app.ex". Walking, it gives the piece's name and note.

Example

paths = ["lib/my_app.ex", "lib/my_app/repo.ex", "mix.exs", "README.md"]
options = %{walk: false, paths: paths, root: "my_app", open: ["lib/"], cursor: "lib/"}
tree = Ascii.new!("file-tree", options: options, parts: true)

{:ok, tree} = Ascii.handle_event(tree, {:key, "down"})
tree.options.cursor
#=> "lib/my_app.ex"

Ascii.describe(tree)
#=> "file tree of my_app: 2 folders, 4 files; at lib/my_app.ex"
<Ascii.Phoenix.live_player id="files" piece="file-tree" options={%{walk: false, paths: @paths}} parts interactive notify />

Ported from src/pieces/file-tree.ts in bas3line/ascii (MIT).

Summary

Functions

entries text for a list of paths, as the paths option takes them: each path's folders are made from it, a path ending in "/" (or holding others) is a folder, and every folder's entries come in the order first given.

Functions

entries(paths)

@spec entries(paths :: [String.t()]) :: String.t()

entries text for a list of paths, as the paths option takes them: each path's folders are made from it, a path ending in "/" (or holding others) is a folder, and every folder's entries come in the order first given.

iex> Ascii.Pieces.FileTree.entries(["lib/app.ex", "lib/app/repo.ex", "mix.exs", "priv/"])
"lib/\n  app.ex\n  app/\n    repo.ex\nmix.exs\npriv/"