Files
relspecgo/docs/TUI_MOUSE_SUPPORT_PLAN.md
T

12 KiB

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.