Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,14 +111,16 @@ $actual -eq $expected
| `Ctrl+R` | Reload catalog |
| `Ctrl+K` | Toggle favorites-only |
| `Alt+S` | Toggle selected-only view |
| `Alt+N` / `Alt+P` | Jump to next/previous invalid field |
| `v` | Cycle category filter |
| `c` | Toggle current category |
| `C` | Open all categories |
| `x` | Clear selected extensions |
| `j` `k` `h` `l` `g` `G` | Vim-style list and hierarchy motion |
| `Esc` | Unwind filter context / exit |
| `Ctrl+C` | Quit immediately |

Full keybindings: [docs/modules/ROOT/pages/ui/keybindings.adoc](docs/modules/ROOT/pages/ui/keybindings.adoc)
Letter shortcuts are case-insensitive, and each `Ctrl`/`Alt` shortcut also accepts its `Shift` variant. Full keybindings: [docs/modules/ROOT/pages/ui/keybindings.adoc](docs/modules/ROOT/pages/ui/keybindings.adoc)

## Requirements

Expand Down
5 changes: 2 additions & 3 deletions docs/modules/ROOT/pages/architecture.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ Startup policy now lives under `application/`: `LiveStartupMetadataLoader` owns

== UI Layer Design

The TUI layer uses an immediate-mode rendering architecture built on the https://github.com/ayagmar/tamboui[TamboUI] framework.
The TUI layer uses an immediate-mode rendering architecture built on the https://github.com/tamboui/tamboui[TamboUI] framework.

=== Component Decomposition

Expand Down Expand Up @@ -172,8 +172,7 @@ CoreTuiController (Orchestration Shell)
├── UiTextConstants UI text content
├── CatalogLoadCoordinator Async catalog lifecycle + startup-overlay timing via reducer intents
├── GenerationFlowCoordinator Async generation lifecycle
├── GenerationStateMachine Allowed generation-state transitions
└── UiTextInputKeys Text-input edit-key normalization
└── GenerationStateMachine Allowed generation-state transitions
....

Reducer-visible UI semantics are now converged for form and extension read-model state. `ProjectRequest`, `ValidationReport`, extension search/filter/read-model summaries, catalog lifecycle semantics, and overlay visibility flags update through reducer intents/effects and live in reducer-owned `UiState`. `UiRenderModel` is assembled immediately before render and carries the derived `metadataPanel`, `extensionsPanel`, `footer`, `generation`, and `startupOverlay` slices. Mutable widget internals such as `TextInputState` and `ListState` stay in adapter/runtime context rather than `UiState`.
Expand Down
2 changes: 1 addition & 1 deletion docs/modules/ROOT/pages/troubleshooting.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Actions:
java --enable-native-access=ALL-UNNAMED -jar target/quarkus-forge.jar
----
. Verify your terminal supports 256-color or true-color (e.g., `echo $TERM`). Recommended: `xterm-256color`, `alacritty`, `kitty`, or `wezterm`.
. On Windows, use Windows Terminal or a recent ConEmu/Git Bash with VT mode enabled. Forge now defaults to the JLine backend on Windows to preserve arrow-key navigation; avoid forcing `tamboui.backend=panama` unless you are debugging backend behavior.
. On Windows, run inside a real console (Windows Terminal, PowerShell, or `cmd.exe`) so the Panama backend can enable virtual-terminal input; Git Bash/MSYS `mintty` does not expose a Win32 console and leaves keys unregistered without `winpty`. Forge defaults to the Panama backend on every platform; set `tamboui.backend=jline3` (or `TAMBOUI_BACKEND=jline3`) only if you need to fall back to JLine.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use the JVM -D form in the fallback instruction.

Line 30 currently shows tamboui.backend=jline3, but users need -Dtamboui.backend=jline3 when launching the jar. As written, the documented system-property override is not executable.

Suggested wording
-. On Windows, run inside a real console (Windows Terminal, PowerShell, or `cmd.exe`) so the Panama backend can enable virtual-terminal input; Git Bash/MSYS `mintty` does not expose a Win32 console and leaves keys unregistered without `winpty`. Forge defaults to the Panama backend on every platform; set `tamboui.backend=jline3` (or `TAMBOUI_BACKEND=jline3`) only if you need to fall back to JLine.
+. On Windows, run inside a real console (Windows Terminal, PowerShell, or `cmd.exe`) so the Panama backend can enable virtual-terminal input; Git Bash/MSYS `mintty` does not expose a Win32 console and leaves keys unregistered without `winpty`. Forge defaults to the Panama backend on every platform; start the JVM with `-Dtamboui.backend=jline3` (or set `TAMBOUI_BACKEND=jline3`) only if you need to fall back to JLine.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
. On Windows, run inside a real console (Windows Terminal, PowerShell, or `cmd.exe`) so the Panama backend can enable virtual-terminal input; Git Bash/MSYS `mintty` does not expose a Win32 console and leaves keys unregistered without `winpty`. Forge defaults to the Panama backend on every platform; set `tamboui.backend=jline3` (or `TAMBOUI_BACKEND=jline3`) only if you need to fall back to JLine.
. On Windows, run inside a real console (Windows Terminal, PowerShell, or `cmd.exe`) so the Panama backend can enable virtual-terminal input; Git Bash/MSYS `mintty` does not expose a Win32 console and leaves keys unregistered without `winpty`. Forge defaults to the Panama backend on every platform; start the JVM with `-Dtamboui.backend=jline3` (or set `TAMBOUI_BACKEND=jline3`) only if you need to fall back to JLine.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/modules/ROOT/pages/troubleshooting.adoc` at line 30, The troubleshooting
note for the backend fallback uses the wrong JVM property syntax, so update the
instruction in the relevant documentation section to use the executable
system-property form with the same symbol, tamboui.backend, as described
alongside the Forge backend fallback. Keep the environment-variable alternative
as-is, but change the property example to the -D form so users can pass it when
launching the jar.


[id="metadata-fallback"]
== Metadata fallback on startup
Expand Down
10 changes: 9 additions & 1 deletion docs/modules/ROOT/pages/ui/keybindings.adoc
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
= TUI Keybindings

Bindings build on the Vim binding set, so motion keys work alongside the arrow keys. Letter shortcuts (`v`, `x`, `f`) are case-insensitive, and every `Ctrl`/`Alt` shortcut also responds to its `Shift` variant (for example `Ctrl+R` and `Ctrl+Shift+R` both reload the catalog).

== Navigation

* `Tab` / `Shift+Tab`: move focus across form, search, list, and submit.
* `Up` / `Down` (or `j` / `k`): list navigation.
* `Left` / `Right` (or `h` / `l`): navigate category hierarchy.
* `Home` / `End`: first/last row.
* `Home` / `End` (or `g` / `G`): first/last row.
* `PgUp` / `PgDn`: previous/next category.

== Focus and Search
Expand All @@ -24,8 +26,14 @@
* `f`: favorite focused extension.
* `Ctrl+J`: jump to next favorite.
* `Ctrl+K`: toggle favorites-only filter.
* `Alt+S`: toggle selected-only filter.
* `Ctrl+Y`: cycle preset-only filter (presets loaded from `code.quarkus.io`).

== Form Validation

* `Alt+N`: focus the next invalid field.
* `Alt+P`: focus the previous invalid field.

== Global Actions

* `?`: open help overlay.
Expand Down
2 changes: 2 additions & 0 deletions docs/modules/ROOT/pages/usage/tui.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ NOTE: `--enable-native-access=ALL-UNNAMED` suppresses Panama FFM warnings from t
* `Ctrl+P`: command palette.
* `?`: help overlay.
* `Ctrl+K`: toggle favorites-only mode.
* `Alt+S`: toggle selected-only mode.
* `Ctrl+J`: jump to next favorite.
* `Alt+N` / `Alt+P`: jump to the next/previous invalid field.

== Submit and Exit

Expand Down
67 changes: 14 additions & 53 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,7 @@
dev/tamboui/tui/bindings/.*\\.properties$
</native.tui.bindings.resource.pattern>

<tamboui.core.version>0.3.0</tamboui.core.version>
<tamboui.annotations.version>0.3.0</tamboui.annotations.version>
<tamboui.panama-backend.version>${tamboui.core.version}</tamboui.panama-backend.version>
<tamboui.jline3-backend.version>${tamboui.core.version}</tamboui.jline3-backend.version>
<tamboui.tui.version>0.3.0</tamboui.tui.version>
<tamboui.widgets.version>${tamboui.tui.version}</tamboui.widgets.version>
<tamboui.version>0.4.0</tamboui.version>
<picocli.version>4.7.7</picocli.version>
<jackson.core.version>2.21.3</jackson.core.version>
<junit.version>6.0.3</junit.version>
Expand All @@ -47,51 +42,14 @@
<native.skip>true</native.skip>
</properties>

<repositories>
<repository>
<id>ossrh-snapshots</id>
<url>https://central.sonatype.com/repository/maven-snapshots/</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
<updatePolicy>never</updatePolicy>
</snapshots>
</repository>
</repositories>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>dev.tamboui</groupId>
<artifactId>tamboui-annotations</artifactId>
<version>${tamboui.annotations.version}</version>
</dependency>
<dependency>
<groupId>dev.tamboui</groupId>
<artifactId>tamboui-core</artifactId>
<version>${tamboui.core.version}</version>
</dependency>
<dependency>
<groupId>dev.tamboui</groupId>
<artifactId>tamboui-panama-backend</artifactId>
<version>${tamboui.panama-backend.version}</version>
</dependency>
<dependency>
<groupId>dev.tamboui</groupId>
<artifactId>tamboui-jline3-backend</artifactId>
<version>${tamboui.jline3-backend.version}</version>
</dependency>
<dependency>
<groupId>dev.tamboui</groupId>
<artifactId>tamboui-tui</artifactId>
<version>${tamboui.tui.version}</version>
</dependency>
<dependency>
<groupId>dev.tamboui</groupId>
<artifactId>tamboui-widgets</artifactId>
<version>${tamboui.widgets.version}</version>
<artifactId>tamboui-bom</artifactId>
<version>${tamboui.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
Expand All @@ -100,18 +58,19 @@
<dependency>
<groupId>dev.tamboui</groupId>
<artifactId>tamboui-tui</artifactId>
<version>${tamboui.tui.version}</version>
</dependency>
<dependency>
<groupId>dev.tamboui</groupId>
<artifactId>tamboui-toolkit</artifactId>
</dependency>
<dependency>
<groupId>dev.tamboui</groupId>
<artifactId>tamboui-panama-backend</artifactId>
<version>${tamboui.panama-backend.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>dev.tamboui</groupId>
<artifactId>tamboui-jline3-backend</artifactId>
<version>${tamboui.jline3-backend.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
Expand Down Expand Up @@ -447,19 +406,21 @@
<dependency>
<groupId>dev.tamboui</groupId>
<artifactId>tamboui-tui</artifactId>
<version>${tamboui.tui.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>dev.tamboui</groupId>
<artifactId>tamboui-toolkit</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>dev.tamboui</groupId>
<artifactId>tamboui-panama-backend</artifactId>
<version>${tamboui.panama-backend.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>dev.tamboui</groupId>
<artifactId>tamboui-jline3-backend</artifactId>
<version>${tamboui.jline3-backend.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package dev.ayagmar.quarkusforge.runtime;

import dev.ayagmar.quarkusforge.ui.AppKeyActions;
import dev.tamboui.tui.bindings.Actions;
import dev.tamboui.tui.bindings.BindingSets;
import dev.tamboui.tui.bindings.Bindings;
import dev.tamboui.tui.bindings.KeyTrigger;
Expand All @@ -10,29 +9,38 @@ final class AppBindingsProfile {
private AppBindingsProfile() {}

static Bindings bindings() {
return BindingSets.standard().toBuilder()
.bind(KeyTrigger.ch('j'), Actions.MOVE_DOWN)
.bind(KeyTrigger.ch('k'), Actions.MOVE_UP)
.bind(KeyTrigger.ch('h'), Actions.MOVE_LEFT)
.bind(KeyTrigger.ch('l'), Actions.MOVE_RIGHT)
.bind(KeyTrigger.ch('g'), Actions.HOME)
.bind(KeyTrigger.ch('G'), Actions.END)
return BindingSets.vim().toBuilder()
.bind(KeyTrigger.ch('/'), AppKeyActions.FOCUS_EXTENSION_SEARCH)
.bind(KeyTrigger.ctrl('f'), AppKeyActions.FOCUS_EXTENSION_SEARCH)
.bind(KeyTrigger.ctrl('F'), AppKeyActions.FOCUS_EXTENSION_SEARCH)
.bind(KeyTrigger.ctrl('l'), AppKeyActions.FOCUS_EXTENSION_LIST)
.bind(KeyTrigger.ctrl('L'), AppKeyActions.FOCUS_EXTENSION_LIST)
.bind(KeyTrigger.ctrl('k'), AppKeyActions.TOGGLE_FAVORITES_FILTER)
.bind(KeyTrigger.ctrl('K'), AppKeyActions.TOGGLE_FAVORITES_FILTER)
.bind(KeyTrigger.ctrl('y'), AppKeyActions.CYCLE_PRESET_FILTER)
.bind(KeyTrigger.ctrl('Y'), AppKeyActions.CYCLE_PRESET_FILTER)
.bind(KeyTrigger.ctrl('j'), AppKeyActions.JUMP_TO_FAVORITE)
.bind(KeyTrigger.ctrl('J'), AppKeyActions.JUMP_TO_FAVORITE)
.bind(KeyTrigger.ctrl('r'), AppKeyActions.RELOAD_CATALOG)
.bind(KeyTrigger.ctrl('R'), AppKeyActions.RELOAD_CATALOG)
.bind(KeyTrigger.ctrl('e'), AppKeyActions.TOGGLE_ERROR_DETAILS)
.bind(KeyTrigger.ch('v'), AppKeyActions.CATEGORY_FILTER_CYCLE)
.bind(KeyTrigger.ctrl('E'), AppKeyActions.TOGGLE_ERROR_DETAILS)
.bind(KeyTrigger.chIgnoreCase('v'), AppKeyActions.CATEGORY_FILTER_CYCLE)
.bind(KeyTrigger.ch('c'), AppKeyActions.TOGGLE_CATEGORY)
.bind(KeyTrigger.ch('C'), AppKeyActions.OPEN_ALL_CATEGORIES)
.bind(KeyTrigger.ch('x'), AppKeyActions.CLEAR_SELECTED_EXTENSIONS)
.bind(KeyTrigger.ch('f'), AppKeyActions.FAVORITE_TOGGLE)
.bind(KeyTrigger.chIgnoreCase('x'), AppKeyActions.CLEAR_SELECTED_EXTENSIONS)
.bind(KeyTrigger.chIgnoreCase('f'), AppKeyActions.FAVORITE_TOGGLE)
.bind(KeyTrigger.ch('?'), AppKeyActions.OPEN_HELP)
.bind(KeyTrigger.ctrl('p'), AppKeyActions.OPEN_COMMAND_PALETTE)
.bind(KeyTrigger.ctrl('P'), AppKeyActions.OPEN_COMMAND_PALETTE)
.bind(KeyTrigger.alt('g'), AppKeyActions.SUBMIT_GENERATION)
.bind(KeyTrigger.alt('G'), AppKeyActions.SUBMIT_GENERATION)
.bind(KeyTrigger.alt('s'), AppKeyActions.TOGGLE_SELECTED_FILTER)
.bind(KeyTrigger.alt('S'), AppKeyActions.TOGGLE_SELECTED_FILTER)
.bind(KeyTrigger.alt('n'), AppKeyActions.NEXT_INVALID_FIELD)
.bind(KeyTrigger.alt('N'), AppKeyActions.NEXT_INVALID_FIELD)
.bind(KeyTrigger.alt('p'), AppKeyActions.PREVIOUS_INVALID_FIELD)
.bind(KeyTrigger.alt('P'), AppKeyActions.PREVIOUS_INVALID_FIELD)
.build();
}
}
Loading
Loading