Skip to content

feat(io,cmd): configurable prompt, clean UX — remove # prefix, Ctrl+C, domain/bean sync - #67

Merged
nyg merged 3 commits into
masterfrom
nyg/feat-configurable-prompt
Jun 6, 2026
Merged

feat(io,cmd): configurable prompt, clean UX — remove # prefix, Ctrl+C, domain/bean sync#67
nyg merged 3 commits into
masterfrom
nyg/feat-configurable-prompt

Conversation

@nyg

@nyg nyg commented Jun 6, 2026

Copy link
Copy Markdown
Owner

Summary

This PR delivers two related improvements: configurable REPL prompt and several UX polish fixes.


1. Configurable prompt with template variables

The default REPL prompt changes from $> to > . Users can override it via $XDG_CONFIG_HOME/jmxsh/config.properties using the prompt key.

Template variables

Variable Value
{server} Connected JMX server (host:port when the URL carries a host, otherwise full URL string); empty when not connected
{domain} Currently selected domain; empty when none
{bean} Currently selected bean; empty when none

Optional blocks

Wrap content in {?...} to hide that section when all variables inside it are empty:

# Show server only when connected
prompt={?[{server}] }> 

# Show full context, cleanly hidden when nothing is selected
prompt={?[{server}] }{?{domain}}{?/{bean}}> 

With {?[{server}] }{?{domain}}{?/{bean}}> :

  • Not connected, nothing selected: >
  • Connected to host:9010, domain java.lang, bean type=Memory: [host:9010] java.lang/java.lang:type=Memory>

2. UX polish

Remove # prefix from normal messagesVerboseCommandOutput.printMessage() no longer prepends #. Errors (printError) keep their # prefix since they go to stderr.

Ctrl+C exits cleanlyUserInterruptException from JLine is caught in the REPL loop; prints Interrupted. and exits cleanly instead of printing the exception class name.

Auto-set domain from bean — When BeanCommand sets a fully-qualified bean (e.g. java.lang:type=Memory), it also sets the session domain to java.lang automatically.

Unset bean when domain changes — When DomainCommand changes the domain, if the current bean doesn't belong to the new domain, the bean is automatically unset with a message.

Help column widthhelp command widened to 11-char columns to fit unsubscribe; header capitalised.


Changes

  • VerboseCommandOutput — remove # from printMessage()
  • HelpCommand — capitalize header; widen format column to 11
  • CliMain — catch UserInterruptException in REPL loop
  • AppConfig — add prompt key (default "> "), update config file template with optional-block examples
  • PromptTemplate (new) — resolves {server}, {domain}, {bean}; adds {?...} optional block support via brace-balanced parser
  • JlineCommandInput — accept Supplier<String> prompt for dynamic re-evaluation
  • CommandCenter — expose getSession() for wiring in CliMain
  • BeanCommand — auto-set domain from resolved bean name
  • DomainCommand — unset bean when domain changes

Tests

  • AppConfigTestprompt property cases
  • PromptTemplateTest (new) — 15 cases covering variables, optional blocks, edge cases
  • BeanCommandTest — domain auto-set from fully-qualified and partial bean names
  • DomainCommandTest — bean unset / keep / no-op cases for domain changes
  • VerboseLevelIT — updated to reflect no # on messages
  • HelpCommandTest — updated expected column width

nyg and others added 2 commits June 6, 2026 12:17
Change the default prompt from "$> " to "> " and allow users to
override it via the existing config file using the "prompt" key.

Template variables are resolved against the current session state on
each readline call:
  {server}  - connected JMX server (host:port or full URL), empty if not connected
  {domain}  - currently selected domain, empty if none
  {bean}    - currently selected bean, empty if none

Example config entries:
  prompt=>
  prompt=[{server}]>
  prompt=[{domain}/{bean}]>

- AppConfig: add "prompt" key with default "> "
- PromptTemplate: new utility class that resolves variables against Session
- JlineCommandInput: accept Supplier<String> so prompt is re-evaluated each readline
- CommandCenter: expose getSession() for wiring in CliMain
- CliMain: wire prompt supplier using a session ref populated after CommandCenter construction

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…rompt blocks, domain/bean sync

- VerboseCommandOutput: remove '#' prefix from printMessage(); errors
  (printError) keep '#' for script parseability
- HelpCommand: capitalize header message; widen command column to 11
  chars to fit longest command name ('unsubscribe')
- CliMain: catch UserInterruptException in the REPL loop and print
  'Interrupted.' instead of propagating the exception
- PromptTemplate: add {?...} optional block syntax — a block is
  rendered only if at least one {var} inside it is non-empty; supports
  nesting via brace-balanced parser. Update AppConfig default config
  examples to show optional-block templates.
- BeanCommand: after setting a fully-qualified bean, auto-set the
  session domain to the domain prefix of the bean name
- DomainCommand: when setting a new domain, unset the session bean if
  it does not belong to that domain

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@nyg nyg changed the title feat(io): configurable REPL prompt with template variables feat(io,cmd): configurable prompt, clean UX — remove # prefix, Ctrl+C, domain/bean sync Jun 6, 2026
Remove the '#' prefix from printError() in VerboseCommandOutput,
PrintStreamCommandOutput, and WriterCommandOutput, and from the
safety-net error handler in CliMain.main(). All output is now
prefix-free.

Update tests: StartupErrorsE2EIT, VerboseLevelIT, CliArgumentsE2EIT.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@sonarqubecloud

sonarqubecloud Bot commented Jun 6, 2026

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
78.3% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

@nyg
nyg merged commit 3b2b3a1 into master Jun 6, 2026
3 of 4 checks passed
@nyg
nyg deleted the nyg/feat-configurable-prompt branch June 6, 2026 21:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant