User-defined segment boundaries#126
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (4)
🚧 Files skipped from review as they are similar to previous changes (4)
📝 WalkthroughWalkthroughThis PR adds custom segment-boundary editing across the data model, segmentation transforms, UI controls, persistence, and navigation. It also updates segment labels, adjacent-edge linking, and test coverage for boundary-aware behavior. ChangesUser-defined segment boundary editing
Estimated code review effort: 5 (Critical) | ~120 minutes Sequence Diagram(s)sequenceDiagram
participant PhraseSlot
participant BoundaryControl
participant SegmentationProvider
participant Interlinearizer
participant InterlinearizerLoader
PhraseSlot->>BoundaryControl: render merge or split button
BoundaryControl->>SegmentationProvider: dispatch.merge or dispatch.split
SegmentationProvider->>Interlinearizer: forceBreakStraddledPhrases before delegating
Interlinearizer->>InterlinearizerLoader: segmentationDispatch.merge/split/move
InterlinearizerLoader->>InterlinearizerLoader: apply transform, autosaveSegmentation
sequenceDiagram
participant InterlinearizerLoader
participant useDraftProject
participant ProjectModals
participant saveInterlinearAnalysis
participant projectStorage
InterlinearizerLoader->>useDraftProject: autosaveSegmentation(delta)
useDraftProject->>useDraftProject: debounce persist, increment segmentationVersion
ProjectModals->>saveInterlinearAnalysis: saveAnalysis(id, analysisJson, segmentationJson)
saveInterlinearAnalysis->>projectStorage: updateAnalysis(token, id, analysis, segmentation)
projectStorage-->>ProjectModals: updated project
ProjectModals->>useDraftProject: markSynced(analysis, segmentation)
Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
cfa0a17 to
69f8147
Compare
f43875e to
c75337e
Compare
11eb61a to
1c939f6
Compare
alex-rawlings-yyc
left a comment
There was a problem hiding this comment.
@alex-rawlings-yyc resolved 1 discussion.
Reviewable status: 0 of 50 files reviewed, all discussions resolved (waiting on alex-rawlings-yyc).
…o I can work on this elsewhere)
Verse-0 superscriptions are ordinary segments now: addBoundaryBefore, removeBoundaryAt, and moveBoundary no longer refuse edits that touch a superscription's interior or its bordering boundaries. The UI-side wall comes out separately. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The resegmented book is derived from the draft's ref-held segmentation, and the auto-save's setDirty(true) bails out of the re-render once the draft is already dirty — so clicking merge/split updated the stored delta without updating the view. useDraftProject now bumps a dedicated segmentationVersion on every boundary edit, and the loader keys the resegment memo on it so the new boundaries take effect in place without remounting the editor. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
After a merge/split a segment no longer corresponds 1:1 to a verse, so the old verse-number header could repeat or skip. Each segment now shows a per-chapter sequential segment number (starting at 0 for a verse-0 superscription) with the verse range it contains beside it, e.g. "2 (2–3)". The labels are built once over the whole book by a new pure segment-labels util so the numbering doesn't depend on which window slice is mounted. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
phrasesStraddlingBoundary finds every phrase a proposed segment boundary would cut (including the gap between fragments of a discontiguous phrase) and pairs each with the split point that severs it cleanly at the boundary. usePhraseLinkByIdGetter exposes a stable, non-subscribing read of the phrase-link map for event-time callers. Both are consumed by the boundary-control rework that follows: one predicate shared by the force-break dispatch and the split-control suppression so the two can't drift apart. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Segment-boundary editing is no longer a separate mode toggled from the view options. Instead: - The between-group slots always carry a boundary control alongside the link icon: a split control inside a segment (hover-revealed with the slot) and a horizontal-fold merge control at a segment boundary in the continuous strip. - The segment list gets an always-visible full-width merge button in the gap between adjacent rows. - Hovering any of these previews the operation: the affected token groups render a new strong phrase-candidate outline (distinct from and outranking hover/focus), and hovered row merges outline and tint the two rows they would join. - The not-mid-phrase rule becomes a UI-only guard sharing one predicate (phrasesStraddlingBoundary) with the dispatch: the split control hides and the cross-segment pull disables at boundaries that would cut a phrase, while the wrapped segmentation dispatch force-breaks straddled phrases for callers that cannot see them. - The verse-0 hard wall comes out of the UI to match the model: superscriptions merge and split like any other segment. Merged-away default verse boundaries render a faint former-boundary tick (formerBoundaryRefs replaces verseZeroSegmentIds in the segmentation context) so a split can restore the original segmentation. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A merge/split hands the views a fresh book object while every token ref survives, and the old code treated that like a book swap: - Interlinearizer reseeded focusedTokenRef to the active verse's first word (or the book's first phrase when a merge removed the active verse's segment start). It now keeps a still-resolving focus and reseeds only when the token no longer exists in the new book. - useSegmentWindow faded and recentered on the new segments identity, snapping away from the point just clicked. A segments change at an unchanged anchor verse now redraws in place with no fade. - ContinuousView's committed active segment kept naming a segment that no longer existed, deactivating every link button until the next navigation; a reconcile effect commits the new id when a segmentation edit changes the focused token's segment without moving focus. The instant-jump reveal also re-centers each frame through the link-slot transition so async arc/morpheme layout can't drift the strip off-center. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Rewrites the segment-boundaries section for the no-edit-mode UX: always-available controls (item 5), superscriptions as ordinary segments (item 6, replacing the hard-wall interim), and silent force-breaking of straddled phrases (new item 7). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
editing Persistence: Open now loads a project's stored segmentation (validated) into the draft, and Save As / Overwrite send segmentationJson alongside the analysis, so custom boundaries survive the full save/open loop instead of being silently wiped. markSynced compares both the analysis and segmentation snapshots, so a boundary edit made during a save round-trip keeps the draft dirty. Boundary edits: the cross-segment pull anchors the moved boundary on the next word token (merging wholly when only trailing punctuation remains), so a pull can no longer strand a punctuation-only segment or record a punctuation ref in addedStarts. Former boundaries are exposed as a word-anchored map so punct-initial verses show the restore tick and split back to the exact default boundary. Boundary controls disable while a phrase mode is active, closing a path that could restore a phrase spanning two segments. Segment window: an explicit segmentationVersion signal (threaded from the loader) replaces the verse-key inference, so a merge absorbing the active verse no longer flashes a recenter fade and a re-tokenized book recenters again. Performance: the loader's book/formerBoundaries memos key on version counters (plus isDraftLoading for the initial load) instead of the draft identity, so gloss autosaves no longer re-run full-book resegmentation; the not-mid-phrase guard is a straddled-boundary set precomputed once per phrase-link change, replacing per-slot link scans and store subscriptions. Cleanups: useBookIndexes owns segmentOrder/fullTokenOrder/wordRefByOrder in its single pass; autosaveDraft unifies the analysis/segmentation autosave pipelines; ContinuousView shares one holdCentered loop and reuses commitPendingActiveSegment; saveAnalysis's command schema documents segmentationJson; user-questions.md describes the shipped always-visible boundary controls.
5e4e6f9 to
a05ca88
Compare
imnasnainaec
left a comment
There was a problem hiding this comment.
@imnasnainaec reviewed 4 files and all commit messages, and made 3 comments.
Reviewable status: 4 of 50 files reviewed, 3 unresolved discussions (waiting on alex-rawlings-yyc).
a discussion (no related file):
After splitting or joining, I find the numbering in the segment view confusing. Rather than (e.g.) 1 (1), 2 (1), 3 (1-2), 4(3), ..., what about dropping the segment number and using lettering, like (e.g.) 1a, 1b, 1c-2, 3, ... ?
a discussion (no related file):
The external jumps aren't quite working in this case: split verse 1 and join the second half with verses 2 and 3. An external move to v2 or v3 jumps to the first half of v1, rather than the 1b-3 segment.
contributions/localizedStrings.json line 47 at r2 (raw file):
"%interlinearizer_tokenChip_defineMorphemes%": "Define morpheme breakdown for {token}", "%interlinearizer_linkButton_crossSegmentDisabledTooltip%": "Only a free edge token of an adjacent segment can be linked across a boundary.", "%interlinearizer_boundaryControl_merge%": "Merge with previous segment",
⛏️ I think "Merge segments" makes morse sense with the current UI.
Replace the per-chapter segment ordinal with verse-based labels (1a, 1b, 1c–2, 3), and match verses to segments by range containment instead of exact start-verse match, so external jumps to a verse inside a merged or split segment land on the segment that contains it.
autosaveSegmentation now clears the persisted segmentation field when the delta has no removed or added starts, not just when it is undefined — an empty delta represents the default segmentation and shouldn't persist a redundant custom object. Extract getSegmentationDispatch helper in the loader test and tighten the move-boundary assertion to check the exact normalized delta.
This change is
Summary by CodeRabbit