Skip to content

feat: Implement comprehensive JLine Curses TUI library with focus indicators and repaint system#1349

Merged
gnodet merged 7 commits intojline:masterfrom
gnodet:feature/curses
Feb 15, 2026
Merged

feat: Implement comprehensive JLine Curses TUI library with focus indicators and repaint system#1349
gnodet merged 7 commits intojline:masterfrom
gnodet:feature/curses

Conversation

@gnodet
Copy link
Copy Markdown
Member

@gnodet gnodet commented Jul 10, 2025

Overview

This PR implements a TUI library for JLine's curses module with interactive components, keyboard/mouse event handling, focus management, and a smart repaint system.

Key Features

Components

  • Label: Static text display with alignment (left, center, right), word wrap, and area fill
  • Input: Single-line text input with cursor navigation, selection, validation, password mode, mouse click-to-position
  • Button: Clickable button with visual states (normal, focused, pressed), click listeners, proper mouseup activation
  • TextArea: Multi-line text editor with scrolling, line wrapping, line numbers, scrollbar, mouse click-to-position
  • List: Scrollable list with single/multiple selection, keyboard navigation, scrollbar, mouse click-to-select
  • Table: Multi-column table with column management, row selection, mouse click-to-select
  • Tree: Hierarchical tree view with expand/collapse, keyboard navigation, mouse click on triangle to toggle, scrollbar
  • Menu: Menu bar with submenus, shortcuts, item actions, drag-to-select across submenus, shadow on dropdowns
  • Box: Titled border container with shortcut key support, focus-aware border styling
  • Checkbox: Toggle checkbox with [x]/[ ] rendering, change listeners, arrow key navigation between siblings
  • RadioButton/RadioGroup: Mutual exclusion radio buttons with (o)/( ) rendering, arrow key navigation
  • ComboBox: Dropdown selector with open/close, keyboard navigation, generic item renderer
  • ProgressBar: Value bar (0.0–1.0) with block characters and optional percentage display
  • Separator: Horizontal/vertical line separator (NoFocus)

Layout System

  • BorderPanel: Five-region layout (Top, Bottom, Left, Right, Center) with center-first shrink order
  • GridPanel: Real grid layout with row/col positioning, rowSpan/colSpan support, even space distribution

Dialog System

  • Dialog: Modal window with Popup + Modal behaviors, auto-centered and auto-sized from preferred size
  • Curses.showMessage(): Simple message dialog with OK button
  • Curses.showConfirm(): Confirmation dialog with OK/Cancel buttons and callback
  • Curses.showInput(): Input dialog with text field and OK/Cancel buttons

Input Handling

  • KeyEvent/KeyParser: Structured keyboard event parsing (arrows, function keys, modifiers)
  • KeyMapBuilder: Pre-parsed KeyEvent integration with JLine's KeyMap system
  • Shortcut keys: Alt+key shortcuts registered automatically when components are added to panels
  • Mouse support: Click-to-position in text components, button click on release, menu drag-to-select, tree expand/collapse on click, close button on press

Focus & Repaint System

  • Visual focus indicators (white borders for focused windows/boxes)
  • Active window tracking — modal dialogs defocus the main window
  • Focus highlight hidden when component loses focus (List, Tree, Table)
  • Tab/Shift+Tab focus cycling, arrow key navigation within checkbox/radio groups
  • Full screen redraw on terminal resize
  • Invalidation-based repaint with upward propagation

Theming

  • All components resolve styles from the theme at draw time via resolveStyle() helper
  • Gray backgrounds for all components (bg:white in terminal 16-color)
  • Semi-transparent window shadows via Screen.darken() — preserves characters with darkened style
  • Menu dropdown shadows
  • Consistent styling: label, button, checkbox, radio, progress, combo, separator styles in DefaultTheme

Demo

  • Interactive CursesDemo showcasing all components
  • Menu-driven navigation between component demos
  • Widgets submenu: Checkbox, Radio, ComboBox, ProgressBar demos
  • Dialogs submenu: Message, Confirm, Input dialogs
  • TextArea with line numbers enabled, progress bar in status area

Testing

Tests passing across test classes:

  • NewWidgetsTest: 25 tests covering Checkbox, RadioButton/RadioGroup, ComboBox, ProgressBar, Separator, GridPanel, Dialog
  • BorderPanelTest: Updated for center-first shrink order
  • VirtualScreenDrawingTest: Updated for title clipping
  • Plus existing tests for KeyEvent, KeyMapBuilder, Menu, Modifiers, Shortcuts, Rendering, Navigation, Invalidation, ThreadSafety

Files Changed

New Files

  • impl/Checkbox.java, impl/RadioButton.java, impl/RadioGroup.java
  • impl/ComboBox.java, impl/ProgressBar.java, impl/Separator.java
  • impl/Dialog.java
  • test/NewWidgetsTest.java

Modified Files

  • Component.java (Modal behavior), Curses.java (GridConstraint, widget/dialog factories)
  • GUI.java (getActiveWindow), Screen.java (darken method)
  • AbstractComponent.java (resolveStyle, focusSibling helpers)
  • AbstractWindow.java (active window border, close on release, preferred size with border)
  • GUIImpl.java (window layout, full redraw on resize, active window tracking)
  • BorderPanel.java (center-first shrink), AbstractPanel.java (skip zero-size)
  • DefaultTheme.java (all new component styles, gray backgrounds, white focus borders)
  • Label.java (theme, area fill, text clipping), Button.java (theme, mouse click on release)
  • Input.java, List.java, Table.java, TextArea.java, Tree.java (theme, mouse handling, focus-aware highlight)
  • Menu.java (drag-to-select, shadow, press/release semantics)
  • VirtualScreen.java (darken method)
  • Box.java (title clipping, focus border)
  • GridPanel.java (real layout algorithm)
  • CursesDemo.java (enhanced demo with all new features)

@gnodet gnodet marked this pull request as draft July 18, 2025 21:56
@gnodet gnodet added the feature label Aug 6, 2025
@gnodet gnodet added this to the 4.0.0 milestone Aug 6, 2025
…icators and repaint system

This commit implements a complete Terminal User Interface (TUI) library for JLine with:

- **Essential Components**: List, Table, Tree, Input, Label, Button, TextArea
- **Layout Containers**: Box, Window, Panel for organizing components
- **Interactive Demo**: Complete CursesDemo showcasing all functionality

- **Focus Indicators**: Yellow borders and titles for focused components
- **Theme Integration**: Consistent styling through DefaultTheme
- **Visual Feedback**: Clear indication of which component has focus

- **Invalidation API**: Components automatically invalidate on state changes
- **Efficient Updates**: Only invalid components are redrawn
- **Focus-Aware**: Automatic invalidation on focus changes
- **Performance**: Minimal screen updates for optimal performance

- **KeyEvent System**: Comprehensive key event processing
- **Keyboard Navigation**: Arrow keys, Tab, Enter, Escape support
- **Modifier Keys**: Ctrl, Alt, Shift detection and handling
- **Shortcut System**: Configurable keyboard shortcuts

- **Comprehensive Tests**: 368+ tests across all modules
- **Virtual Screen Testing**: Mock screen for component testing
- **Integration Tests**: End-to-end functionality verification
- **Code Quality**: Spotless formatting and clean architecture

- **POSIX Commands**: Comprehensive POSIX command implementation
- **Build System**: Clean Maven build with proper dependency management
- **Documentation**: Updated module documentation and examples

The implementation follows TUI best practices from libraries like Ratatui and Cursive,
providing a modern, efficient, and user-friendly terminal interface experience.
The KeyParser class is a utility class with only static methods.
Adding a private constructor prevents instantiation and fixes the
missing-explicit-ctor warning that was causing compilation to fail
with -Werror.
Convert 5 test files from main()-based tests to JUnit 5 @test methods
so they are picked up by Surefire:
- KeyEventTest, KeyMapBuilderTest, MenuFixesTest, ModifierKeyTest,
  ShortcutTest

Add 3 new test files for additional coverage:
- ComponentRenderingTest: Label rendering/alignment, Input editing,
  Button clicks/rendering
- KeyNavigationTest: List/Table/Tree navigation and selection
- InvalidationTest: invalidation lifecycle and parent propagation

Add curses TUI documentation page at website/docs/advanced/curses-tui.md

Total tests: 131 (up from 37)
@gnodet
Copy link
Copy Markdown
Member Author

gnodet commented Feb 14, 2026

Augment Review

Rebased onto current master and added the following improvements:

Tests converted to JUnit 5

The 5 test files that used main() methods were not being picked up by Surefire. Converted them all to proper JUnit 5 @Test methods:

  • KeyEventTest (15 tests) - character, arrow, function, special, modifier, and unknown key parsing
  • KeyMapBuilderTest (4 tests) - InputEvent creation and unmatched input parsing
  • MenuFixesTest (5 tests) - menu selection, toggle, switch, and item execution
  • ModifierKeyTest (16 tests) - Ctrl, Alt, Shift, and combined modifier key handling
  • ShortcutTest (5 tests) - component shortcut interface, Box focus delegation, panel shortcut registration

New test coverage

Added 3 new test files covering gaps:

  • ComponentRenderingTest (21 tests) - Label rendering with all alignments, multiline, empty text; Input text manipulation, cursor movement, selection, password mode, change listeners; Button rendering, click listeners, pressed state
  • KeyNavigationTest (20 tests) - List focus navigation (up/down/boundaries), single/multi selection, add/remove/clear; Table creation, focus navigation, selection; Tree node creation, expansion, leaf detection, add/remove children
  • InvalidationTest (8 tests) - Components start invalid, draw clears invalid, invalidate() marks invalid, parent propagation, focus change invalidation, same-state no-op

Documentation

Added website/docs/advanced/curses-tui.md covering:

  • Getting started with dependency and minimal example
  • All components (Label, Input, Button, TextArea, List, Table, Tree, Menu, Box)
  • Layout system (BorderPanel, GridPanel)
  • Event handling (KeyEvent, MouseEvent, shortcuts)
  • Invalidation/repaint system
  • Theming with style name conventions
  • Builder API with full example
  • Screen/VirtualScreen usage

Result

  • 131 tests passing (up from 37 before, all 13 test classes now run via Surefire)
  • Demo module compiles cleanly
  • Spotless formatting applied

@augmentcode
Copy link
Copy Markdown

augmentcode Bot commented Feb 14, 2026

🤖 Augment PR Summary

Summary: Adds a higher-level curses TUI framework to JLine with structured keyboard events, richer widgets, focus/shortcut handling, and expanded rendering/test support.

Changes:

  • Extends the curses Component API to return handled/unhandled status for input, accept parsed KeyEvents, and expose invalidation hooks.
  • Introduces terminal-level KeyEvent/KeyParser plus curses InputEvent/KeyMapBuilder to unify keyboard and mouse bindings.
  • Adds new interactive widgets (Label, Input, Button, TextArea, List, Table, Tree) and enhances existing Menu/Box behavior.
  • Implements shortcut-key focus dispatch (Alt+key) in panels and improves focus-triggered visual styling for windows/boxes.
  • Expands the Screen contract (clear/refresh/cursor/size) and enhances VirtualScreen for buffer-based rendering and tests.
  • Adds a new CursesDemo module entry and a detailed documentation page describing the TUI/builder APIs.

🤖 Was this summary useful? React with 👍 or 👎

Copy link
Copy Markdown

@augmentcode augmentcode Bot left a comment

Choose a reason for hiding this comment

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

Review completed. 5 suggestions posted.

Fix All in Augment

Comment augment review to trigger a new review at any time.

Comment thread curses/src/main/java/org/jline/curses/impl/Button.java Outdated
Comment thread curses/src/main/java/org/jline/curses/impl/Box.java
Comment thread curses/src/main/java/org/jline/curses/impl/Menu.java Outdated
Comment thread curses/src/main/java/org/jline/curses/impl/Input.java
Comment thread website/docs/advanced/curses-tui.md Outdated
gnodet and others added 4 commits February 14, 2026 13:43
- Button: use getScreenPosition() in doDraw to render at correct
  position instead of always at (0,0)
- Box: default null border to Single to prevent NPE in switch
- Menu: replace isShortcutMatch with matchShortcut using global KeyMap
  to support function keys (F1/F3) and chorded shortcuts (C-x C-s)
- Input: add handleKey(KeyEvent) for character input, arrow navigation,
  backspace/delete, home/end, Ctrl+A select all
- TextArea: add handleKey(KeyEvent) for character input, arrow
  navigation, enter, backspace/delete, home/end, page up/down
- Button: add handleKey(KeyEvent) for Enter and Space activation
- Docs: clarify that GUIImpl.redraw() currently redraws all windows
  each cycle; invalidation state is available but selective repaint
  is not yet implemented
Add 'curses' as a built-in demo in both demo.sh and demo.bat,
mapping to org.jline.demo.CursesDemo.
- AbstractWindow: add Tab/Shift+Tab to cycle focus between focusable
  components in the window. Collects all non-NoFocus leaf components
  and cycles through them in tree order.
- AbstractWindow: move Alt+letter shortcut check before focused
  component delegation so shortcuts always work regardless of which
  component has focus. Search recursively through all nested containers.
- AbstractWindow: 'q' to close now only fires when no component is
  focused, or when the focused component doesn't handle it (so typing
  'q' in an Input works correctly).
- KeyParser: add Shift+Tab (backtab, ESC[Z) parsing
- KeyMapBuilder: bind key_btab capability for Shift+Tab
Add new form widgets (Checkbox, RadioButton/RadioGroup, ComboBox,
ProgressBar, Separator), modal dialog system (showMessage, showConfirm,
showInput), and real GridPanel layout with row/col spanning.

Improve UI polish: theme-based styling for all components (gray
backgrounds), semi-transparent window shadows via Screen.darken(),
white focused borders, proper window sizing from preferred size,
scrollbars for TextArea and List, title clipping, label area filling.

Add mouse support: click-to-position in TextArea/List/Tree/Table/Input,
button click on release, menu drag-to-select across submenus, tree
expand/collapse on triangle click, close button on press.

Fix focus management: active window tracking for border styling, modal
dialogs defocus main window, arrow key navigation for checkboxes/radio
buttons, hide focus highlight when component loses focus.

Fix rendering bugs: BorderPanel center-first shrink order, skip
zero-size components, guard against negative dimensions on resize,
full screen redraw on terminal resize.

Add comprehensive tests and enhanced demo showcasing all new features.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@gnodet
Copy link
Copy Markdown
Member Author

gnodet commented Feb 15, 2026

augment review

@augmentcode
Copy link
Copy Markdown

augmentcode Bot commented Feb 15, 2026

This pull request is too large for Augment to review. The PR exceeds the maximum size limit of 100000 tokens (approximately 400000 characters) for automated code review. Please consider breaking this PR into smaller, more focused changes.

@gnodet gnodet marked this pull request as ready for review February 15, 2026 09:23
@augmentcode
Copy link
Copy Markdown

augmentcode Bot commented Feb 15, 2026

This pull request is too large for Augment to review. The PR exceeds the maximum size limit of 100000 tokens (approximately 400000 characters) for automated code review. Please consider breaking this PR into smaller, more focused changes.

@gnodet gnodet merged commit 8af6866 into jline:master Feb 15, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant