Skip to main content

lib/bb/tui/panels/help.ex

defmodule BB.TUI.Panels.Help do
  @moduledoc """
  Help popup — overlay showing all available keyboard shortcuts.

  Renders the keyboard reference as a single `ExRatatui.Widgets.Markdown`
  widget so the content is a plain markdown string (`@help_markdown`)
  rather than 50+ hand-built `Text.Line` rows. Markdown handles section
  headings, bullet lists, inline code (used for keybindings), and
  scroll offsets natively.

  Pure function — returns a Popup widget struct.
  """

  alias ExRatatui.Style
  alias ExRatatui.Text.Line
  alias ExRatatui.Text.Span
  alias ExRatatui.Widgets.Block
  alias ExRatatui.Widgets.Markdown
  alias ExRatatui.Widgets.Popup

  @help_markdown """
  ## Global

  - `q` — Quit
  - `[` / `]` — Switch top-level tab (Control Panel / Visualization)
  - `Tab` — Cycle to the next panel
  - `Shift+Tab` — Cycle to the previous panel
  - `1` / `2` / `3` / `4` / `5` — Jump directly to the panel whose
    title shows the matching `[N]` badge
  - `?` — Toggle this help
  - `a` — Arm robot
  - `d` — Disarm robot
  - `f` — Force disarm (error state only)

  ## Visualization tab

  - `←` / `→` or `h` / `l` — Orbit the camera
  - `↑` / `↓` or `k` / `j` — Tilt the camera
  - `+` / `-` — Zoom in / out
  - `r` — Reset the camera
  - `m` — Cycle render mode (auto / kitty / sixel / iterm2 / half-block / braille / ascii)

  ## Events panel

  - `j` / `↓` — Scroll down
  - `k` / `↑` — Scroll up
  - `⏎` — Show event details
  - `p` — Pause / resume stream
  - `c` — Clear all events

  ## Commands panel

  - `j` / `↓` — Select next command
  - `k` / `↑` — Select previous command
  - `⏎` — Execute (or enter argument edit mode)

  ## Command edit mode

  - `Tab` / `↓` — Focus next argument
  - `Shift+Tab` / `↑` — Focus previous argument
  - `⏎` — Execute with current values
  - `Esc` — Exit edit mode (keeps values)
  - `Backspace` — Delete last char of focused arg
  - `←` / `→` — Cycle enum value (enum-typed args only)
  - `h` / `l` — Cycle enum, or append to non-enum buffer

  ## Joints panel

  - `j` / `↓` — Select next joint
  - `k` / `↑` — Select previous joint
  - `l` / `→` — Increase position (1% of range)
  - `h` / `←` — Decrease position (1% of range)
  - `L` — Increase position (10% of range)
  - `H` — Decrease position (10% of range)

  Commanded targets render as a hollow marker on the position bar.

  ## Parameters panel

  - `j` / `↓` — Select next parameter
  - `k` / `↑` — Select previous parameter
  - `l` / `→` — Increase value (1% of range, or +1 / +0.1 when unbounded)
  - `h` / `←` — Decrease value (1% of range, or -1 / -0.1 when unbounded)
  - `L` — 10× step
  - `H` — 10× step (down)
  - `⏎` — Toggle boolean parameter
  - `t` — Cycle to the next bridge tab

  Bridge-tab edits route through `BB.Parameter.set_remote`.

  ---

  `j` / `k` scroll this popup. Any other key closes it.
  """

  @doc """
  Renders the help popup as a Popup widget with optional scroll offset.

  ## Examples

      iex> %ExRatatui.Widgets.Popup{content: %ExRatatui.Widgets.Markdown{}} =
      ...>   BB.TUI.Panels.Help.render(0)

      iex> %ExRatatui.Widgets.Popup{content: %ExRatatui.Widgets.Markdown{content: md}} =
      ...>   BB.TUI.Panels.Help.render(5)
      iex> md =~ "## Global"
      true
  """
  @spec render(non_neg_integer()) :: struct()
  def render(scroll_offset \\ 0) do
    content = %Markdown{
      content: @help_markdown,
      wrap: true,
      scroll: {scroll_offset, 0}
    }

    %Popup{
      content: content,
      percent_width: 60,
      percent_height: 70,
      block: %Block{
        title: title_line(),
        borders: [:all],
        border_type: :double,
        border_style: %Style{fg: :cyan}
      }
    }
  end

  @doc """
  Returns the full markdown source rendered inside the popup. Exposed
  so callers (and tests) can introspect the help content without
  spinning up the widget tree.
  """
  @spec markdown() :: String.t()
  def markdown, do: @help_markdown

  defp title_line do
    %Line{
      spans: [
        %Span{content: " 🤖 ", style: %Style{}},
        %Span{content: "Help ", style: %Style{fg: :white, modifiers: [:bold]}}
      ]
    }
  end
end