[codex] Add selection-aware document stats - #88
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bb7f41dfbd
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| char: update.state.selection.main.head - cursor.from, | ||
| }); | ||
| } | ||
| if (options.onSelectionStatsChange && update.selectionSet) { |
There was a problem hiding this comment.
Update selection stats on all selection changes
This listener only recalculates selection stats when update.selectionSet is true, but in CodeMirror selection positions can change implicitly during document edits (for example, typing over an active selection or replacing the whole document on open/new) without setting selectionSet. In those flows, the footer can keep showing stale selectionStats from a previous selection until the user explicitly moves/selects again, which makes the stats incorrect for normal editing and file-open workflows.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Pull request overview
This PR adds selection-aware document statistics to the renderer: it centralizes document stat calculations into a helper, computes word/character counts for CodeMirror selections, and displays those selection stats in the app footer alongside overall document totals.
Changes:
- Introduce
getDocumentStats/getSelectionStatshelper and unit tests for the helper. - Extend CodeMirror update listener and editor/component props to emit selection stats to the app.
- Update the Chrome footer to show selection stats on the left and document totals on the right.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/index.ts | Registers the new document stats unit test in the unit test entrypoint. |
| tests/documentStats.test.ts | Adds unit coverage for document/selection stat helpers. |
| src/shared/types.ts | Adds a shared SelectionStats type for cross-component usage. |
| src/renderer/lib/documentStats.ts | Introduces the new document/selection stat helper functions. |
| src/renderer/editor/codemirror/extensions.ts | Computes selected text from CodeMirror selections and emits selection stats via callback. |
| src/renderer/components/CodeMirrorEditor.tsx | Threads the new onSelectionStatsChange callback down into CodeMirror extensions. |
| src/renderer/components/Chrome.tsx | Displays selection stats in the footer UI. |
| src/renderer/app.tsx | Uses the shared helper for document stats and stores selection stats in app state for the footer. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| import assert from "node:assert/strict"; | ||
| import { | ||
| getDocumentStats, | ||
| getSelectionStats, | ||
| } from "../src/renderer/lib/documentStats"; | ||
|
|
||
| { | ||
| const stats = getDocumentStats("One two\nthree"); | ||
| assert.deepEqual(stats, { | ||
| words: 3, | ||
| chars: 13, | ||
| lines: 2, | ||
| readingMinutes: 1, | ||
| }); | ||
| } |
| export type SelectionStats = { | ||
| hasSelection: boolean; | ||
| words: number; | ||
| chars: number; | ||
| }; |
| if (options.onSelectionStatsChange && update.selectionSet) { | ||
| const selectedText = update.state.selection.ranges | ||
| .filter((range) => !range.empty) | ||
| .map((range) => update.state.doc.sliceString(range.from, range.to)) | ||
| .join("\n"); | ||
| options.onSelectionStatsChange(getSelectionStats(selectedText)); | ||
| } |
| <span className="min-w-0 truncate"> | ||
| {selectionStats?.hasSelection | ||
| ? `selection: ${selectionStats.words} words / ${selectionStats.chars} chars` | ||
| : "no selection"} | ||
| </span> | ||
| <div className="flex shrink-0 items-center gap-3"> |
Summary
Validation