feat: mirror pane (p), cursor memory, clean up help dialog
- Add Mirror pane keybinding p (for 'Pane'), SSH restored on s - Add session-scoped cursor memory per directory - Fix cursor memory bug: DisplayName() adds trailing / for directories - Fix remote mirror: use active.Path instead of mount.RemotePath - Remove F-key/Mouse/b/c entries from F1 help dialog - Remove Mirror from ShortHelp footer (F-keys only) - Add missing letter-key bindings to help: p, s, a, n, x
This commit is contained in:
parent
c8d6976030
commit
cd877ab584
5 changed files with 201 additions and 18 deletions
88
plans/mirror-and-cursor-memory.md
Normal file
88
plans/mirror-and-cursor-memory.md
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
# Feature Plan: Mirror Pane & Per-Directory Cursor Memory
|
||||
|
||||
## Feature 1: Mirror active pane directory to opposite pane
|
||||
|
||||
### Keybinding research
|
||||
- **Midnight Commander (MC)**: `Alt-i` — makes the other panel equal to current directory
|
||||
- **Total Commander**: `Ctrl-PgDn` opens directory under cursor in opposite panel
|
||||
- **Far Manager**: `Ctrl-Left/Right` — opens in opposite panel
|
||||
|
||||
**Recommendation**: Bind to `p` (for "Pane"). `Ctrl-i` sends the same byte as `Tab` (ASCII 0x09) so it conflicts with Switch. `p` is free, accessible, and "Pane" reflects the meaning.
|
||||
|
||||
### How it works
|
||||
1. Read active pane's current path (including remote mount state)
|
||||
2. Apply that path to the passive (opposite) pane
|
||||
3. If active is in a remote mount, also clone the remote mount stack to the passive pane
|
||||
4. Reload both panes to reflect the change
|
||||
|
||||
### Code changes
|
||||
|
||||
#### [`internal/ui/keymap.go`](internal/ui/keymap.go)
|
||||
- Add `Mirror` key binding field to `KeyMap` struct
|
||||
- Bind to `"p"` with help text `"p"` / `"mirror pane"`
|
||||
|
||||
#### [`internal/ui/model.go`](internal/ui/model.go)
|
||||
- Add handler `handleMirrorPane()`:
|
||||
1. Get active pane path and remote mount state
|
||||
2. Switch passive pane to match (copy remote stack if applicable)
|
||||
3. Reload passive pane (using `reloadPane` or `reloadRemotePane`)
|
||||
4. Set status: `"Mirrored: <path>"`
|
||||
- Add key match case before the `default` switch
|
||||
|
||||
---
|
||||
|
||||
## Feature 2: Per-directory cursor position memory (session scope)
|
||||
|
||||
### Current state
|
||||
- `enterSelected()` saves `pane.Path` to history for back-nav, then reloads target dir with `selected.Name` as preserve key — but `selected.Name` is the name of the directory being entered, not a cursor anchor
|
||||
- `goParent()` pops history and reloads parent using the child directory name as preserve — cursor lands on the directory we came from
|
||||
- **Missing**: When navigating back into a previously-visited directory, there's no saved cursor position for it
|
||||
|
||||
### Design
|
||||
Add a `cursorMemory` field to `BrowserPane` — a `map[string]string` mapping **directory path → last selected entry display name**.
|
||||
|
||||
This integrates cleanly with the existing `SetEntries(entries, preserveKey)` / `FindSelected()` infrastructure.
|
||||
|
||||
### Flow
|
||||
|
||||
```
|
||||
enterSelected() / enterRemoteDir():
|
||||
1. Save to cursorMemory: pane.Path → selected entry's Name
|
||||
2. Push history (existing)
|
||||
3. Set path, reload (existing)
|
||||
4. The reload already uses preserve=selected.Name for the new dir,
|
||||
but cursorMemory will help when coming back later
|
||||
|
||||
reloadPane() / reloadRemotePane():
|
||||
1. Try preserve key first (existing behavior)
|
||||
2. If preserve is empty, check cursorMemory[pane.Path]
|
||||
and use that as preserveKey instead
|
||||
```
|
||||
|
||||
### Code changes
|
||||
|
||||
#### [`internal/ui/pane.go`](internal/ui/pane.go)
|
||||
- Add field to `BrowserPane`: `CursorMemory map[string]string`
|
||||
- Method `SaveCursor(path string, name string)` — stores cursor position
|
||||
- Method `LoadCursor(path string) string` — retrieves saved cursor
|
||||
|
||||
#### [`internal/ui/model.go`](internal/ui/model.go)
|
||||
- In `enterSelected()` (line ~1886): after `pane.PushHistory(pane.Path)`, add `pane.SaveCursor(pane.Path, selected.Name)`
|
||||
- In `enterRemoteDir()` (line ~5726): same save logic
|
||||
- In `goParent()`: save cursor before navigating away (already partially done via history)
|
||||
- In `reloadPane()` (line ~1672): after existing preserve logic, if no preserve key and directory has cursor memory, use it
|
||||
- In `reloadRemotePane()` (line ~5535): same fallback
|
||||
|
||||
---
|
||||
|
||||
## Files modified
|
||||
| File | Changes |
|
||||
|------|---------|
|
||||
| `internal/ui/keymap.go` | Add `Mirror` field, binding `p` |
|
||||
| `internal/ui/pane.go` | Add `CursorMemory` field + methods |
|
||||
| `internal/ui/model.go` | Add `handleMirrorPane()`, save/restore cursor in navigation methods |
|
||||
|
||||
## Not changed
|
||||
- `internal/fs/` — storage layer unaffected
|
||||
- `internal/config/` — no config changes needed
|
||||
- `internal/theme/` — no theme changes needed
|
||||
Loading…
Add table
Add a link
Reference in a new issue