Skip to content

Copy games between tabs, and notice when a file changes on disk - #3

Merged
dancechessmaster merged 1 commit into
mainfrom
tabs/copy-and-watch
Sep 7, 2026
Merged

Copy games between tabs, and notice when a file changes on disk#3
dancechessmaster merged 1 commit into
mainfrom
tabs/copy-and-watch

Conversation

@dancechessmaster

Copy link
Copy Markdown
Contributor

Phase 2 of the multi-file work, on top of #2.

Copy to. Right-click ▸ Copy to ▸ another open tab appends the selected games to that file and writes it back once. Duplicates are decided by the moves (a new signature column: start position + main line, check/mate suffixes stripped), not by headers — two files of one tournament disagree about names and events, never about the moves. Copying again lands nothing and says so.

The new column bumps the cache schema (PRAGMA user_version = 2). Older caches are upgraded in place and report needs_rebuild; the app re-imports them (≈2 s per 100k games). One thing to know from the test: the index on the new column must be created after the upgrade step, not in the CREATE batch — on an old cache that batch ran first and failed on "no such column".

File watcher. A DispatchSource per open file. The app's own writes are told apart by the modification date recorded after each write; an editor's save-by-rename re-arms the watch. Banner: Reload (take the file as it is now — this file's sessions are detached first, since a re-import renumbers games) or Keep Mine (next save replaces the file, .pgn.bak kept).

What to review first: DatabaseStore.copyGames / writeBack / reloadFromDisk, SessionRegistry.detach(store:), and Database::open in db.rs (the upgrade path).

Checked with the hooks (DCS_AUTO_COPY, DCS_AUTO_WATCH_OUT, DCS_AUTO_WATCH_RELOAD, DCS_AUTO_TAB_SAVE):

  • copy games 1–2 of A into B → 1 lands (the other id does not exist in A), B's file gains the game
  • copy again → 0 copied, 1 already there
  • external append while open → banner up, count unchanged
  • external append + Reload → 7 → 9 games, banner down
  • the app's own save → no banner

Not done: drag and drop between tabs; a menubar Copy item (SwiftUI Commands cannot observe the open-store list).

🤖 Generated with Claude Code

https://claude.ai/code/session_01F9o9DSzZas4GsekCpG5M8T

The second half of the multi-file work.

**Copy to.** Right-click ▸ Copy to ▸ another open tab appends the selected
games to that file and writes it back once. "Already there" is decided by
the moves, not the headers: a `signature` column hashes the start
position and the main line (check and mate suffixes stripped), because two
files of one tournament disagree about the event's name, how a player is
spelled and sometimes who had White, and the moves are the one thing both
copies got from the same scoresheet. Copying the same games again lands
nothing and says so.

The column means a schema change. `PRAGMA user_version` now carries the
schema version; an older cache is upgraded in place so it opens and reports
`needs_rebuild`, which the app treats as stale — a two-second re-import
against the alternative of query paths that tolerate every past layout.
The index on the new column has to be created after the upgrade step, not
in the CREATE batch: on an old cache that batch ran first and failed on
"no such column".

**The file is watched.** A `DispatchSource` on the path; the app's own
writes are told apart by the modification date recorded after each one,
and an editor's save-by-rename — which swaps the inode under the
descriptor — re-arms the watch. The banner offers Reload (take the file as
it is now; this file's sessions are detached first, since a re-import
renumbers the games and a session keeping an old id could save into a
different one) or Keep Mine (carry on; the next save replaces the file,
with the .pgn.bak kept).

Checked with the hooks: copying two games lands the one that is not a
duplicate; copying again lands none; an external append raises the banner
and leaves the count alone; Reload takes it to the new count; the app's
own save raises nothing. Rust: 37 tests.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F9o9DSzZas4GsekCpG5M8T
@dancechessmaster
dancechessmaster merged commit 3167ea2 into main Sep 7, 2026
1 check passed
@dancechessmaster
dancechessmaster deleted the tabs/copy-and-watch branch September 7, 2026 06:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant