diff --git a/CHANGELOG.md b/CHANGELOG.md index 289a984..974c687 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- **Terminal slot drag & drop reorder**: terminal slots can now be reordered by dragging a dedicated **grip handle** (`LuGripVertical`) in the slot titlebar onto any other slot in the same workspace grid. New module `src/workbench/terminal_slot_dnd.rs` defines the `application/x-blxcode-terminal-slot` MIME payload, the `TerminalSlotDragService` Leptos context (active drag meta + ghost position, non-reactive `StoredValue` session flag with generation guard against stale deferred updates), and helpers `set_drag_payload` / `read_drag_payload` / `is_terminal_drag` / `ghost_style`. Drag source and drop target are resolved live by `slot_id` (not array index) via the new `WorkbenchService::terminal_slot_index(workspace_id, slot_id)` accessor, so repeated reorders compose without stale indices. The grid uses HTML5 native drag & drop (`dragstart` / `dragover` / `drop`), with the deferred `try_set_active(gen, meta)` pattern so Leptos doesn't re-render mid-`dragstart` (which would cancel the drag on WebKitGTK / Wry). Permutation runs in pure-Rust `reorder_workspace_slots` against `slot_ids`, `slot_agent_labels`, and `slot_pane_states` in parallel; PTYs are not unmounted because the `For` key is `slot.id` and `terminal_key` stays stable across the reorder. Drag-disabled states: configurator open, full-size slot active, collapsed sidebar. Drag visuals: source slot at `opacity: 0.55`, target slot with `3px dashed var(--accent)` outline (inset via `outline-offset: -3px`), and a transluscent ghost-preview overlay (`.ws-term-slot-ghost`, `2px dashed` border) at the drop target's grid cell — sized via percentage `grid_template` math so it tracks the live grid dims. To keep `dragover` reaching the slot wrapper while xterm canvases would otherwise capture pointer events, `.ws-term-grid--drag-active .ws-term-slot:not(--drag-source) .ws-term-cell__xterm { pointer-events: none }` is applied while a drag is in flight. New i18n key `WsTermDragHandleAria` (handle aria-label / tooltip) authored in all 13 locales. 3 new unit tests in `state.rs` (`reorder_permutes_parallel_vectors`, `reorder_noop_on_same_index`, `reorder_moves_first_slot_to_second`) pin the pure-Rust permutation semantics. Cross-workspace transfer, drag of individual split panes, and a custom HTML5 drag-image (`setDragImage`) are **out of scope** — `setDragImage` with live or cloned DOM proved to crash WebKitGTK in the Tauri webview under Wry; the current accent-dashed target outline + transluscent source slot is the stable Linux-safe UX. + - **Code preview drag-range selection + right-click handoff to terminals and agent**: the new `CodeView` now supports **drag-based line range selection** — press the left mouse button on a line and drag up or down to extend the selection (`code-view__row--selected` highlight follows continuously). The selection model moved from `Option` to an ordered `Option<(usize, usize)>` 1-based inclusive range; single-clicks still toggle a single line, and `Escape` clears nothing implicitly (it closes the new context menu only). A window-level `mouseup` listener (installed once per `CodeView` mount, cleaned up via `on_cleanup`) ends drags even when the cursor leaves the gutter. `.code-view` gained `user-select: none` so accidental text selection no longer fights the row drag. A new **right-click context menu** (`src/workbench/file_preview/code_context_menu.rs`) opens at the click position whenever the user invokes `contextmenu` on a row; if the click lands outside the current range the selection is first replaced with that single line, otherwise the existing range stays. The menu is grouped into four sections: **Snippet → Insert into terminal** (lists every terminal in every workspace via the new cross-workspace enumerator `list_terminal_targets_all_workspaces` — the preview's own workspace is moved to the front with a localized "current" badge), **Full context block → Insert into terminal** (wraps the snippet in a `⟪ BLXCode attached context ⟫` envelope so the receiving terminal CLI parses it just like a workspace handoff), **Snippet → Attach to agent** (per-workspace `upsert_workspace_agent_context` against the new `AgentContextKind::FileSnippet` kind), and **Clipboard** (`Copy snippet`, `Copy line range`, `Copy raw text` via `navigator.clipboard.writeText` with per-action toast feedback). Cross-workspace inserts and agent attaches add a `source workspace:` line to the snippet/envelope header so the model can disambiguate when the file lives in a different workspace than the target. New helper `build_file_snippet_block` in `src/workbench/file_preview/util.rs` produces fenced markdown blocks (clamped to in-range indices, UTF-8 safe; 6 unit tests cover single-line, range, cross-workspace header, no-language fence, UTF-8 codepoints, and out-of-range clamping). New `render_file_snippet_envelope` in `src/workbench/agent_context_handoff.rs` emits the BLXCode-style handoff envelope without the heavy memory/plans/images sections (2 unit tests cover the in-workspace and cross-workspace variants). `AgentContextItem` gained an optional `content: Option` field on both `src/agent_wire.rs` and `src-tauri/src/agent/protocol.rs` so file-snippet items can ship their fenced block inline; the existing six `AgentContextItem` constructors across the codebase (memory/learning notes + categories, plans, terminal session, "Memory" fallback) now pass `content: None` explicitly. Backend `render_context_prompt` in `src-tauri/src/agent/session_orchestrator.rs` partitions `FileSnippet` items into a dedicated `Attached file snippets (verbatim, line-numbered headers):` prompt section that renders each item's inline content; `render_agent_context_block` in `agent_context_handoff.rs` mirrors this with an `## Attached file snippets` section (memory/plans filters now skip snippet items). Toasts use `WorkbenchService`'s existing `ToastService`. A global `mousedown` window listener closes the menu on any outside click; `Escape` closes too. Drag selection works on both `Code` and `Text` files since both route through the same `CodeView`. 22 new i18n keys (`CodeViewMenuAria`, `CodeViewMenuSectionSnippetTerminal/SnippetAgent/EnvelopeTerminal/Clipboard`, `CodeViewMenuWorkspaceGroup`, `CodeViewMenuTerminalSlotLabel`, `CodeViewMenuAttachAgentLabel`, `CodeViewMenuNoTerminals`, `CodeViewMenuCopySnippet/Range/Raw`, `CodeViewMenuPreviewWorkspaceBadge`, and six `CodeViewToast*` variants for success/failure) were authored with real translations in all 13 locales (en, de, fr, es, it, pt_br, pl, hu, ru, ja, ko, zh_cn, zh_tw) and use `{workspace}`, `{terminal}`, `{slot}`, `{agent}`, `{error}` placeholders. CSS adds `.code-context-menu` and friends with sections, workspace-group headers, slot sublists, accent-pill `code-context-menu__badge`, and themed hover via `--overlay-2`. The `WorkspaceTerminalGroup` helper in `agent_context_handoff.rs` filters shell workspaces via the existing `is_shell_workspace` predicate. - **Closeable Terminals tab + Settings without workspace**: every center tab — including the pinned Terminals tab — now exposes a close button. Clicking the Terminals close button raises a new confirmation overlay (`src/workbench/close_terminals_tab_dialog/`) with a 3-second countdown that keeps the primary button disabled; confirming routes through `WorkbenchService::close_center_terminals_tab`, which saves the workspace, terminates its PTYs, and pushes it onto the recent list (same path as the sidebar close). Closing the last non-Terminals tab in a real workspace likewise triggers `close_workspace` so the welcome screen reappears when no workspaces remain. **Settings** can now open without an active workspace: `open_center_settings_tab` lazily provisions an ephemeral "shell workspace" (empty `cwd`, `configuring: false`, no terminal slots) that hosts only the Settings tab and is hidden from the sidebar via the new `is_shell_workspace` filter; closing the shell's Settings tab disposes the shell automatically. `ensure_center_tabs` was renamed to `repair_center_tab_state` and no longer auto-reinserts a Terminals tab; `open_center_terminals_tab` is the explicit reopener and `open_new_terminal` calls it before appending a slot. `HarnessUiService` gained a `close_terminals_confirm` signal + generation guard (so rapid re-opens cancel stale timers); the harness keyboard handler swallows shortcuts while the dialog is up and routes `Escape` to dismiss. New command palette entry **Terminals** (`PaletteAction::OpenTerminalsTab`, `CmdTermTitle/Sub`) reopens the Terminals tab without spawning a new PTY. `finalize_workspace_close` centralizes wizard-draft cleanup (`workspace_drafts` + `workspace_config_steps`) so every close path drops state. 7 new i18n keys (`CmdTermTitle`, `CmdTermSub`, `CenterTabCloseTerminalsTitle/Body/Confirm/Cancel`, `CenterTabCloseAria`) localized into all 13 locales. 4 new unit tests (`center_tab_tests`) cover the repair semantics, empty-tabs branch, dangling active-id repair, and shell-workspace predicate. - **Code preview with line numbers, syntax highlighting & row selection**: the file preview now ships a dedicated `CodeView` (`src/workbench/file_preview/code_view.rs`) that handles every source-code file with a real two-column layout — a sticky line-number gutter (right-aligned, tabular numerals, hairline divider) and an `hljs`-colored code column — instead of the prior plain `
` fallback. Clicking any row toggles a selection highlight (accent-soft background + accent-color left bar, click again to clear) so users can mark and refer back to a specific line. Backend `classify_kind` in `src-tauri/src/fs_entries.rs` now distinguishes `FileKind::Code` (Rust/TS/JS/JSX/TSX/MJS/CJS, Python, Go, Java/Kotlin/Scala/Groovy/Gradle, Swift/Obj-C, C/C++/C#/F#/VB, Ruby/PHP/Lua/Perl/Dart/R/Julia, Clojure/Elixir/Erlang/Haskell/Elm/Nim/Zig/OCaml, HTML/Vue/Svelte/CSS/SCSS/Sass/Less, JSON/JSON5/JSONC/TOML/YAML/XML/Plist, Shell/Bash/Zsh/Fish/PowerShell/Bat/Cmd, SQL/GraphQL/Protobuf/Thrift/HCL/Terraform/Nix, Dockerfile/Makefile/CMake, diff/patch) from plain `FileKind::Text` (txt/log/ini/conf/env/properties/csv/tsv/gitignore/editorconfig); both kinds route through `CodeView`, but only `Code` gets syntax highlighting. The 11-test fs_entries unit suite now asserts the new mapping including ts/tsx/js/py/go/html/json → Code and txt/log/env/gitignore → Text. The frontend bridge (`tauri_bridge.rs`) mirrors the new `FileKind::Code` variant. New module `src/workbench/file_preview/hljs_glue.rs` lazy-loads the vendored highlight.js 11.11 common bundle (`public/vendor/highlight/highlight.min.js`, ~127 KiB, 38 languages) via a `