Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
7abd4f8
feat: ✨ use pager for multi-page styles in terminal
joelostblom May 4, 2026
b9da415
style: 💄 centralize title and subtitle
joelostblom May 4, 2026
f93c1de
style: 💄 color multi-page output the same as single page
joelostblom May 4, 2026
29020d8
style: 💄 add spacing around hr
joelostblom May 4, 2026
c9368bf
feat: ✨ use textual to more easily navigate multi-page terminal content
joelostblom May 4, 2026
8e656a1
style: 💄 style like terminal app
joelostblom May 4, 2026
a9d04bb
style: 💄 minor contrast imporovements
joelostblom May 4, 2026
7f977a2
perf: ⚡️ improve performance by pre-loading all content
joelostblom May 4, 2026
d95d618
feat: ✨ use datatable for more feature and better perf
joelostblom May 5, 2026
40ed4e3
fix: 🐛 Deal with literal `|` in tables
joelostblom May 5, 2026
cf2f377
perf: ⚡️ use dedicated terminal rendering instead of going through ma…
joelostblom May 5, 2026
e7cf9f9
style: 💄 use correct colors everywhere
joelostblom May 5, 2026
5b7f70e
style: 💄 further fine tune the styling
joelostblom May 5, 2026
d2306dd
perf: ⚡️ debounce so that table is not loaded if quickly scrolling th…
joelostblom May 5, 2026
7420b31
feat: ✨ implement search and sort of tables
joelostblom May 5, 2026
99fcbfd
feat: ✨ hide resources from navigation that don't match the search term
joelostblom May 5, 2026
dac29ed
style: 💄 make search icon yellow
joelostblom May 5, 2026
75eba59
style: 💄 display shortcuts and selections more clearly
joelostblom May 5, 2026
196e9fb
feat: ✨ allow column navigation
joelostblom May 5, 2026
dd65a4f
feat: ✨ add support for copying selection
joelostblom May 6, 2026
bdf4cba
fix: 🐛 tweak keyboard shortcuts and their display
joelostblom May 6, 2026
e4cf545
style: 💄 style toasts more nicely
joelostblom May 6, 2026
753dcec
fix: 🐛 remove redundant caption
joelostblom May 6, 2026
5aa4bab
fix: 🐛 remove esc for quitting
joelostblom May 6, 2026
d9bd63e
refactor: ♻️ Clean up imlementation
joelostblom May 6, 2026
ff55ece
refactor: ♻️ reuse existing markdown rendering path for stdout
joelostblom May 6, 2026
048ea8f
chore: 🔧 make mypy happy
joelostblom May 6, 2026
523fa6e
chore: 🔧 just run all
joelostblom May 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 9 additions & 16 deletions docs/design/interface/cli.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -182,13 +182,13 @@ human-friendly way in the terminal. It has the following signature that
is positional as well as keyword-based:

``` {.bash filename="Terminal"}
seedcase-flower view [SOURCE] [STYLE]
seedcase-flower view [SOURCE] [MODE]
```

For example:

``` {.bash filename="Terminal"}
seedcase-flower view SOURCE --style STYLE
seedcase-flower view SOURCE --mode stdout
```

The diagram below shows the flow of inputs and outputs for `view`.
Expand All @@ -199,27 +199,20 @@ The diagram below shows the flow of inputs and outputs for `view`.
flowchart LR
source("datapackage.json<br>[SOURCE: file, https,<br>gh/github]")
view("view")
style_opt("--style<br>[option]")
output("Output<br>[Terminal]")
mode_opt("--mode<br>[option]")
output("Output<br>[TUI or stdout]")

source --> view
style_opt --> view
mode_opt --> view
view --> output
```

`view` takes a `SOURCE` and `--style` argument like `build`, with two
differences:
`view` takes a `SOURCE` and an optional `--mode` argument, with two modes:

- No output files are generated---`view` only displays the metadata in
the terminal.
- No configuration file is used. The only way to change the output is
via `--style` with one of the built-in styles.
- `tui` opens an interactive terminal interface.
- `stdout` prints a plain terminal representation that can be piped to
other tools.

`view` intentionally has no configuration file support; it's meant for
quick, lightweight inspection of a Data Package's metadata and terminal
display also limits customisation options.

::: callout-tip
Want a different style for viewing the metadata? Check out our
[contribute a style](/docs/guide/contribute-style.qmd) guide.
:::
15 changes: 7 additions & 8 deletions docs/design/interface/python.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,11 @@ flowchart TD

### {{< var done >}} `view()`

`view()` takes the same parameters as `build()`: `source` and `style`.
Unlike `build()`, `view()`'s `style` parameter only accepts built-in
one-page styles (the terminal displays a single page) and ignores custom
styles and the configuration file. For details about the parameters, see
[`view()`](/docs/reference/view.qmd).
`view()` takes a `source` and a display `mode`. Unlike `build()`,
`view()` does not use styles, custom templates, output files, or the
configuration file. The metadata is shown in an interactive TUI by
default, or printed to stdout when `mode="stdout"`. For details about
the parameters, see [`view()`](/docs/reference/view.qmd).

The internal flow of `view()` is shown in the diagram below.

Expand All @@ -95,10 +95,9 @@ The internal flow of `view()` is shown in the diagram below.
%%| fig-cap: "Diagram of the internal flow of functions and objects in the `view()` CLI function."
flowchart TD
source:::input --> parse_source{{"parse_source()"}} --> address
style_cfg[style]:::input --> Config
mode[mode]:::input
address --> read_properties{{"read_properties()"}} --> properties
properties & Config --> build_sections{{"build_sections()"}} --> output["list[BuiltSection]"]
output --> pretty_print{{"pretty_print()"}}
properties & mode --> output{{"TUI or stdout"}}

classDef input fill:#FFF
```
41 changes: 27 additions & 14 deletions docs/guide/cli.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -96,24 +96,20 @@ terminal, so some aspects of it might not display as expected here.

```{python}
#| echo: false
!uv run seedcase-flower view gh:seedcase-project/example-seed-beetle
!uv run seedcase-flower view --mode stdout gh:seedcase-project/example-seed-beetle
```
:::

### Styling terminal output
### Plain terminal output

Use the `--style` flag to format the terminal output with any of the
[built-in view styles](/docs/reference/ViewStyle.qmd). For example:
By default, `view` opens an interactive TUI. Use `--mode stdout` to
print a plain terminal representation that can be piped to tools like
`less`:

```{.bash filename="Terminal"}
seedcase-flower view --style quarto-one-page gh:seedcase-project/example-seed-beetle
seedcase-flower view --mode stdout gh:seedcase-project/example-seed-beetle | less -R
```

<!-- TODO: Update this after another one page style is added so it doesn't use the default style. -->

This output will look identical to the output above, since
`quarto-one-page` is the default style for `view`.

::: {.callout-tip collapse="true" icon="false"}
### Output

Expand All @@ -122,13 +118,30 @@ terminal, so some aspects of it might not display as expected here.

```{python}
#| echo: false
!uv run seedcase-flower view --style quarto-one-page gh:seedcase-project/example-seed-beetle
!uv run seedcase-flower view --mode stdout gh:seedcase-project/example-seed-beetle
```
:::

`view` only works with single-page
[built-in styles](/docs/reference/Style.qmd); multi-page styles are not
supported.
### Interactive TUI

The default `view` mode shows the package and resources in a left-hand
table of contents and the selected section in a scrollable content pane:

```{.bash filename="Terminal"}
seedcase-flower view gh:seedcase-project/example-seed-beetle
```

In the TUI, use `j` and `k` or the arrow keys to move through the table
of contents. Press `l` or the right arrow to focus the current page's
table. Press `l` or the right arrow again to select columns, and `h` or
the left arrow to move back through selected columns, row selection, and
the table of contents. Use `ctrl+d` and `ctrl+u` to move six items down
or up. For tables, use `s` to cycle sorting through the columns and
directions, `ctrl+f` or `/` to search all tables, `c` or `y` to copy the
selected row or column, and `q` or `ctrl+q` to quit. Press `?` to show
all keyboard shortcuts, and press `?` again to close them. The sorted
column shows an arrow for ascending or descending order, and the table
of contents hides resources whose tables have no search matches.

::: callout-important
`view` is only configurable via command line flags. This means that any
Expand Down
25 changes: 7 additions & 18 deletions docs/guide/contribute-style.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,9 @@ should be short, descriptive, and distinct from existing built-in
styles. It should be given in snake case (e.g., `my_new_style`).

::: callout-note
A terminal style for the `view` command must be a single-page output
style, meaning it can only use a single `[[one]]` section. `view`
ignores `output-path` since it doesn't output files and single-page
styles can be used by `build` as well.
The `view` command can display built-in styles with one or more
sections. Multi-section styles are rendered as one paged terminal
document, with each section labelled by its `output-path`.
:::

## Adding the style as built-in
Expand All @@ -63,27 +62,17 @@ license, or schema fields. Remember to give your templates descriptive
names. The `.qmd` extension serves as an example; Jinja2 can produce any
plain text format (e.g., `.html`, `.md`, `.yml`).

Finally, add your style to the appropriate style enum(s) in
`src/seedcase_flower/styles.py`. All styles are defined in the `Style`
enum, while styles for terminal output with `view` are also added to
`ViewStyle`. For example, if `your_new_style` is your new style, you
would include it in `Style` like so:
Finally, add your style to the style enum in
`src/seedcase_flower/styles.py`. Build styles are defined in the `Style`
enum. For example, if `your_new_style` is your new style, you would
include it in `Style` like so:

``` {.python filename="src/seedcase_flower/styles.py"}
class Style(Enum):
# ...
your_new_style = "your_new_style"
```

If your style is also a terminal style for the `view` command, add it
below the existing styles in the `ViewStyle` enum as well:

``` {.python filename="src/seedcase_flower/styles.py"}
class ViewStyle(Enum):
# ...
your_new_style = "your_new_style"
```

::: callout-important
For the new style to work properly, the string value of the enum member
(e.g., `"your_new_style"`) must exactly match the folder name.
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ dependencies = [
"python-jsonpath>=2.0.2",
"rich>=14.3.3",
"seedcase-soil>=0.11.0",
"textual>=8.2.5",
]

[project.urls]
Expand Down
3 changes: 1 addition & 2 deletions src/seedcase_flower/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@
from .cli import build, view
from .config import Config
from .sections import Content, Many, ManyContent, One
from .styles import Style, ViewStyle
from .styles import Style

__all__ = [
"build",
"view",
"Config",
"Style",
"ViewStyle",
"Content",
"One",
"Many",
Expand Down
28 changes: 20 additions & 8 deletions src/seedcase_flower/cli.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Functions for the exposed CLI."""

from enum import Enum
from pathlib import Path
from typing import Any, Optional

Expand All @@ -20,7 +21,7 @@
from seedcase_flower.build_sections import build_sections
from seedcase_flower.config import Config
from seedcase_flower.internals import _number
from seedcase_flower.styles import Style, ViewStyle
from seedcase_flower.styles import Style
from seedcase_flower.write_sections import write_sections

app = setup_cli(
Expand All @@ -30,6 +31,13 @@
)


class ViewMode(Enum):
"""Ways to display `view` output in the terminal."""

tui = "tui"
stdout = "stdout"


@app.command()
def build(
source: str = "datapackage.json",
Expand Down Expand Up @@ -92,7 +100,7 @@ def view(
source: str = "datapackage.json",
/, # End of positional-only args
*, # Start of keyword-only params
style: ViewStyle = ViewStyle.quarto_one_page,
mode: ViewMode = ViewMode.tui,
) -> None:
"""Display the contents of a `datapackage.json` in a human-friendly way.

Expand All @@ -103,17 +111,21 @@ def view(
in the repo root (in the format `gh:org/repo`, which can also include
reference to a tag or branch, such as `gh:org/repo@main` or
`gh:org/repo@1.0.1`).
style: The style used to display the output in the terminal. Must be a
single-page style.
mode: The terminal display mode. Use `tui` for an interactive interface
or `stdout` for plain output that can be piped to other tools.
"""
address: Address = parse_source(source)
properties: dict[str, Any] = read_properties(address)
check(properties, error=True)
built_sections = build_sections(properties, Config(style=Style[style.name]))
if mode == ViewMode.tui:
from seedcase_flower.tui import run_textual_viewer

run_textual_viewer(properties)
return

console = Console(theme=CONSOLE_THEME)
# TODO move back console theme? will it be used in CDP?
print() # One line separation between the command and the datapackage title
console.print(Markdown(built_sections[0].content))
for section in build_sections(properties, Config(style=Style.quarto_one_page)):
console.print(Markdown(section.content))


def main() -> None:
Expand Down
6 changes: 0 additions & 6 deletions src/seedcase_flower/styles.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,3 @@ class Style(Enum):
quarto_one_page = "quarto_one_page"
quarto_resource_listing = "quarto_resource_listing"
quarto_resource_tables = "quarto_resource_tables"


class ViewStyle(Enum):
"""Subset of styles suitable for terminal output (single-page only)."""

quarto_one_page = "quarto_one_page"
Loading
Loading