213 lines
12 KiB
Markdown
213 lines
12 KiB
Markdown
# TUI mouse support plan
|
|
|
|
Issue: #46
|
|
Status: design only; this document does not implement mouse input.
|
|
|
|
## 1. Current implementation and scope
|
|
|
|
The editor is created in `cmd/relspec/edit.go` by
|
|
`ui.NewSchemaEditorWithConfigs(...).Run()`. `pkg/ui/editor.go` owns the
|
|
`tview.Application`, `tview.Pages`, and application lifecycle. The current
|
|
code never calls `Application.EnableMouse`, so tcell mouse reporting is off.
|
|
The module uses tview v0.42.0 and tcell/v2 v2.13.9.
|
|
|
|
The first implementation should add `--no-mouse` to the `edit` Cobra command
|
|
only. The flag is a local boolean, defaulting to false, and should be passed
|
|
explicitly into the editor (prefer an options/config field rather than a
|
|
package-global or environment variable). It must not affect convert, inspect,
|
|
merge, or other commands. There is no environment-variable or persistent
|
|
configuration setting in this issue: a command-line opt-out is predictable,
|
|
visible in `edit --help`, and avoids adding configuration precedence rules.
|
|
|
|
At startup, the editor should call `app.EnableMouse(!noMouse)` before
|
|
`Run()`. `--no-mouse` must mean that the application does not enable terminal
|
|
mouse reporting and that no custom mouse handlers are relied upon. Keyboard
|
|
behavior must remain identical in both modes.
|
|
|
|
Likely implementation files are `cmd/relspec/edit.go`,
|
|
`pkg/ui/editor.go`, focused TUI mouse helpers/tests under `pkg/ui`, and a
|
|
short user-facing note in the command help or TUI documentation. Do not
|
|
refactor unrelated screens or data operations.
|
|
|
|
## 2. Widget and screen coverage
|
|
|
|
The application composes `Pages`, `Flex`, `TextView`, `List`, `Table`, `Form`,
|
|
`Button`, `InputField`, `DropDown`, `TextArea`, `CheckBox`, and `Modal`.
|
|
Vendored tview confirms mouse handlers exist for all of those relevant
|
|
primitives, including focus on left-down, list/table selection, button clicks,
|
|
form child dispatch, dropdown opening/drag selection, text-area cursor and
|
|
scrolling, and modal button dispatch. `Pages`, `Flex`, and `Form` forward events
|
|
to their children.
|
|
|
|
The coverage plan is:
|
|
|
|
* Main menu (`pkg/ui/main_menu.go`): left click focuses/selects a list entry;
|
|
second activation opens it; buttons and exit confirmation remain reachable.
|
|
* Schema, table, domain, object, relation, and database screens: click a row
|
|
to select it; double-click the row to perform the same action as the
|
|
keyboard Enter/selected callback where opening is meaningful; scroll lists
|
|
and tables; click each action button.
|
|
* Tables (`schema_screens.go`, `table_screens.go`, and object/relation tables):
|
|
tview's table handler provides selection and scrolling, but it does not
|
|
provide application-specific double-click activation. Add a small reusable
|
|
wrapper/helper for the table instances that need it. It must preserve the
|
|
existing selected row/column behavior and invoke the same callback as Enter,
|
|
not duplicate mutation logic.
|
|
* Forms (`load_save_screens.go` and the form-building screen files): click an
|
|
input to focus it, click buttons to activate them, click a dropdown to open
|
|
it and choose an option, scroll multiline help/text areas, and retain all
|
|
existing keyboard Tab/Shift-Tab, shortcut, Enter, and Escape behavior.
|
|
* Dialogs (`pkg/ui/dialogs.go` plus confirmation/error/success modals): modal
|
|
buttons are clickable and the modal keeps focus above the underlying page.
|
|
Clicking outside a modal must not activate the hidden page or dismiss a
|
|
destructive confirmation. Escape and the existing button-key behavior stay
|
|
authoritative.
|
|
* The planned file browser and connection-string builder from issue #44 must
|
|
use the same contracts: clickable entries/buttons and scrolling, with
|
|
keyboard navigation and explicit cancel/accept paths. #46 should not
|
|
implement #44's widgets; it should define the integration point and test
|
|
them when #44 lands.
|
|
|
|
Do not promise drag semantics for every widget. Drag is appropriate for text
|
|
selection/cursor movement and dropdown selection where tview already supports
|
|
it. For ordinary list/table navigation, a click selects and the wheel scrolls;
|
|
row dragging should not mutate data.
|
|
|
|
## 3. Exact mouse action contract
|
|
|
|
| Widget/type | Left down/click | Double click | Wheel/drag | Keyboard fallback |
|
|
| --- | --- | --- | --- | --- |
|
|
| Main/list menu | focus and select row | invoke row selected callback | scroll list | arrows, Enter, shortcuts |
|
|
| Data table | focus and select cell/row | invoke the screen's existing open/edit action for the selected row | vertical/horizontal scroll as supported by tview | arrows, PageUp/PageDown, Enter, existing shortcuts |
|
|
| Button | focus | same as one activation, never duplicate the callback | none | Tab/Shift-Tab, Enter/Space and existing shortcut |
|
|
| Input field | focus; place cursor if supported | no destructive action | text-area behavior if provided by tview | typing, arrows, Home/End, Tab, Escape |
|
|
| Text area/help | focus and position cursor | select word only where tview supports it; no application action | scroll; drag text selection if supported | arrows, PageUp/PageDown, standard editing keys |
|
|
| Dropdown | focus/open and choose the hit option | same as click; no duplicate selection | drag through options only while open | arrows, Enter, Escape, Tab |
|
|
| Checkbox | toggle on click | no second toggle | none | Space and existing form navigation |
|
|
| Modal | focus/click visible button | same button action once | no underlying-page scrolling | Tab/Shift-Tab, Enter, Escape, existing button keys |
|
|
| Blank/border/title area | focus containing primitive where useful | none | no mutation | current screen shortcuts |
|
|
|
|
Right and middle clicks should have no application action in the first
|
|
release. Wheel events should be consumed only by the scrollable primitive
|
|
under the pointer. Double-click timing/translation should come from tview/
|
|
tcell; custom code must not fire the action once for both the click and the
|
|
double-click. Any custom table wrapper needs a small state machine or tview
|
|
mouse action handling that is tested for this property.
|
|
|
|
## 4. tview gaps and implementation boundaries
|
|
|
|
Enabling mouse support is not sufficient for the desired behavior. tview's
|
|
built-in Table handler selects cells and scrolls but has no repository-specific
|
|
row-open callback on double click. Existing screen code also wires keyboard
|
|
input captures directly on individual widgets, so mouse actions must call the
|
|
same screen callbacks rather than route through synthetic key events.
|
|
|
|
Use tview's `MouseHandler`/`WrapMouseHandler` contracts and `setFocus` rather
|
|
than reading terminal coordinates in each screen. A reusable table adapter
|
|
may embed `*tview.Table`, delegate ordinary actions to the original table
|
|
handler, and add the screen's double-click callback. Keep the adapter in
|
|
`pkg/ui` and use it only where a row-opening action exists. Do not modify the
|
|
vendored tview copy.
|
|
|
|
The `Pages`/`Modal` dispatch order must be verified: a visible modal consumes
|
|
its click before the page below it. Page transitions should happen only in the
|
|
existing callbacks, so a stale hidden page cannot receive a click.
|
|
|
|
## 5. Keyboard, terminal, and copy/paste behavior
|
|
|
|
Mouse is an enhancement, never a requirement. Every acceptance path must be
|
|
reachable with the existing keyboard controls, including load/save, navigation,
|
|
editing, confirmations, cancel, and exit. `--no-mouse` is the regression mode
|
|
for proving this contract.
|
|
|
|
Mouse reporting is terminal capability dependent. On local terminals it is
|
|
negotiated by tcell; tmux and SSH can suppress, translate, or fail to pass
|
|
mouse reporting depending on their configuration. The application must still
|
|
start and remain keyboard usable if mouse reporting is unavailable or broken.
|
|
Documentation should state that terminal/tmux configuration may be required,
|
|
and that SSH behavior depends on the remote terminal path. Windows Terminal and
|
|
other Windows console hosts should be treated as supported only insofar as the
|
|
selected tcell backend reports mouse events; the CLI must not assume POSIX
|
|
escape sequences or add platform-specific code in this issue.
|
|
|
|
Enabling mouse capture normally prevents terminal-native selection/copy from
|
|
seeing ordinary button-drag events. Document the standard workaround: hold the
|
|
terminal's bypass modifier (commonly Shift, terminal-dependent) for selection,
|
|
or use `--no-mouse` when native copy/paste is the priority. Do not implement a
|
|
second clipboard protocol. Input-field/text-area copy/paste must continue to
|
|
use tview/tcell paste handling and keyboard shortcuts; verify that enabling
|
|
mouse does not intercept paste events.
|
|
|
|
## 6. Test strategy using tcell simulation
|
|
|
|
Add focused tests rather than attempting a full interactive end-to-end test.
|
|
Use `tcell.NewSimulationScreen("")`, `screen.Init()`, construct the editor or
|
|
an isolated primitive tree, and inject events with the actual API:
|
|
`SimulationScreen.InjectMouse(x, y, buttons, mod)` and `InjectKey(...)`.
|
|
Coordinates must be derived from the primitive's drawn rectangle or fixed by a
|
|
small deterministic test layout; do not use arbitrary coordinates without
|
|
checking the rendered screen.
|
|
|
|
Minimum cases:
|
|
|
|
1. Default editor configuration enables mouse; the explicit disabled option
|
|
leaves it disabled. If the Application API is not observable directly,
|
|
test through the simulation screen's event path plus a constructor-level
|
|
option assertion.
|
|
2. A list click changes focus/selection, and double-click invokes the existing
|
|
selected action exactly once.
|
|
3. A table click selects the expected row/cell, wheel events change the visible
|
|
offset, and double-click invokes the row action exactly once.
|
|
4. Form button, input field, checkbox, and dropdown clicks match their
|
|
keyboard callbacks.
|
|
5. A modal button click acts on the modal and cannot activate the underlying
|
|
page; Escape still cancels.
|
|
6. `--no-mouse` leaves keyboard selection/activation unchanged and mouse
|
|
injection has no application effect.
|
|
7. Existing dialogs and screen transitions do not leave a stale mouse capture
|
|
after a page is removed.
|
|
|
|
Prefer callback counters and selected-index assertions over screen-text-only
|
|
assertions. Run the relevant `pkg/ui` tests with `go test -race ./pkg/ui` and
|
|
run the full repository test suite if time/resources permit.
|
|
|
|
## 7. Rollout and acceptance criteria
|
|
|
|
Implementation is ready for review when:
|
|
|
|
* `relspec edit --help` documents `--no-mouse` and mouse is enabled by default.
|
|
* Only the edit TUI is affected; non-TUI commands have no changed behavior.
|
|
* Main screens, tables, lists, forms, dropdowns, buttons, text areas, and
|
|
visible dialogs support the action contract above.
|
|
* Keyboard-only operation is complete and verified with `--no-mouse`.
|
|
* Modal clicks cannot fall through to an underlying page.
|
|
* Table double-click behavior is explicit, tested, and does not duplicate
|
|
activation.
|
|
* tcell simulation tests cover default-on, opt-out, selection, scrolling,
|
|
activation, dialog focus, and keyboard fallback.
|
|
* `go test -race ./pkg/ui`, appropriate command tests, `go test ./...`,
|
|
formatting, and `git diff --check` pass (or any limitation is recorded).
|
|
* User-facing docs explain tmux/SSH/Windows variability and the terminal
|
|
modifier workaround for native copy/paste.
|
|
|
|
Roll out in two implementation slices if needed: first application option,
|
|
standard tview handlers, tests, and documentation; second only the reusable
|
|
table double-click adapter and screen wiring. Do not block the first slice on
|
|
issue #44, but do not claim #44's future widgets are covered until they use the
|
|
same contract.
|
|
|
|
## 8. Open decisions and dependencies
|
|
|
|
* Confirm whether the project wants a public editor options type or a small
|
|
`SetMouseEnabled`/constructor parameter; avoid a global flag.
|
|
* Confirm the preferred terminal copy modifier in project documentation, since
|
|
tmux, SSH clients, and Windows Terminal differ.
|
|
* Decide whether horizontal wheel events should be supported where tview/table
|
|
exposes them; vertical scrolling is mandatory, horizontal is optional.
|
|
* Decide whether double-click opens every data table or only tables with an
|
|
unambiguous row action. The plan recommends the latter.
|
|
* Confirm #44's file-browser and connection-builder primitive choices before
|
|
wiring their mouse tests.
|
|
* Confirm CI has a stable non-terminal environment for simulation-screen tests;
|
|
no real terminal, tmux session, database, or network should be required.
|