$ show dy-sh/obsidian-remember-cursor-position
This is a single-file Obsidian plugin (TypeScript) that automatically persists and restores the cursor position, selection, and scroll offset for every markdown note in a vault. The core logic in main.ts hooks into Obsidian's workspace events (file-open, quit, rename, delete) and uses a polling interval (every 100ms) to detect cursor/scroll changes without relying on global key events. State is stored in a JSON file (configurable, defaults to the plugin directory), with settings for default position on open, save cadence, and pruning rules for orphaned, stale, or excessive entries. The plugin deliberately avoids scrolling when opening a note via a section link by detecting the Obsidian 'is-flashing' CSS marker. Architecturally it is a classic Obsidian plugin: an ES module compiled via Rollup into a single CommonJS bundle, with the settings UI built from the modern SettingGroup API requiring minAppVersion 1.11.0. The main implementation concentrates all feature logic in one 500-line class, relying on Obsidian's private/unstable APIs (marked with @ts-ignore) to read scroll positions and leaf IDs. Data flow is strictly in-memory + async JSON file writes: the path is read from disk at load, pruned, and periodically flushed on a timer (minimum 5s) and on quit. This is not a hybrid research repo; it is a dedicated end-user application plugin. The workmanship exceeds typical plugin boilerplate: the state-comparison logic avoids redundant writes, the pruning layer handles three independent criteria, and the footnote-detection heuristic for the 'before footnotes' option is a genuinely non-obvious feature. However, it is held back by a monolithic design (one giant class), a polling loop instead of event-driven cursor capture, multiple @ts-ignore workarounds against stale Obsidian internals, and a dependency list that is several major versions behind its ecosystem.
The LLM identified 4 files worth highlighting for reuse:
The ephemeral state change detector and equality checker (isEphemeralStatesEquals, checkEphemeralStateChanged) implements a clean, dependency-free pattern for throttled persistence: it polls the current editor state, diffs against the last-recorded state, and only writes when meaningful change occurred. This is a reusable anti-spam pattern for any editor or form that needs to persist navigational state without overwhelming storage.
The setCursorToBeforeFootnotes method uses a regex (/^\s*\[\^[^\]]+\]:\s/) to locate markdown footnote definitions and positions the cursor on the last non-blank line before the first footnote block. This is a self-contained, extractable content-analysis heuristic useful in any markdown-document tooling that needs to navigate around footnotes or trailing reference sections.
The pruneDb() method combines three independent retention policies (orphan removal by vault existence, age-based cutoff, and most-recently-visited count cap using a sorted eviction) in a single idempotent pass. This is a reusable data-retention pattern for any local JSON-backed cache that wants to grow unbounded.
The restoreEphemeralState() flow demonstrates a robust guard against duplicate restores: it tracks loaded leaf IDs and a 'loadingFile' flag to avoid re-applying saved state when a view is merely re-focused. The 'is-flashing' guard to skip restore on section-linked navigation is an elegant, framework-specific adaptation that could be ported to other apps with similar link-highlighting behavior.