Skip to content

feat: multi-caret editing (Ctrl+Click, per-caret insert/delete, single-step undo)#105

Merged
tig merged 16 commits into
developfrom
copilot/add-multi-caret-support
May 14, 2026
Merged

feat: multi-caret editing (Ctrl+Click, per-caret insert/delete, single-step undo)#105
tig merged 16 commits into
developfrom
copilot/add-multi-caret-support

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented May 13, 2026

  • Multi-caret editing: core implementation (insert, delete, toggle, anchor tracking)
  • Constitution compliance: R1 (IBackgroundRenderer), R2 (Rune-based), R8 (spec brief), R9 (ted wiring)
  • CR feedback: multi-caret Enter applies IndentationStrategy (like single-caret)
  • CR feedback: multi-caret Backspace uses smart indentation delete (like single-caret)
  • Tests exercise actual code paths via InvokeCommand (Command.NewLine, Command.DeleteCharLeft)
  • Merge conflicts with develop resolved (clipboard commands + multi-caret editing coexist)
  • Fix CI failures: SearchHitRendererTests updated to account for MultiCaretRenderer always present in BackgroundRenderers
  • CR feedback: MultiCaretRenderer handles UTF-16 surrogate pairs safely (no crash on non-BMP characters like emoji)
  • CR feedback: MultiCaretRenderer scopes caret painting to wrapped segment element range (fixes misplaced carets in word-wrap mode)
  • Docs: multi-caret documented in README + examples/ted/docs/multi-caret.md for future help browser
  • CR feedback: MultiCaretRenderer promoted to IOverlayRenderer (draws after elements, not before) so carets are never overwritten by text
  • CR feedback: Exclusive segment-end bound check (>= instead of >) prevents duplicate carets at word-wrap boundaries
  • CR feedback: Render additional carets at EOL positions — extracted IsOffsetInSegment allows offset == segEnd only at true line end (not wrap boundaries)

Copilot AI and others added 2 commits May 13, 2026 14:33
…elete, single-step undo)

- New Editor.MultiCaret.cs partial with AdditionalCaretOffsets, ToggleCaretAt, ClearAdditionalCarets
- Ctrl+Click adds/removes additional carets in Editor.Mouse.cs
- Editing commands (insert/delete/backspace/newline) iterate all carets in reverse offset order inside RunUpdate() for undo collapse
- Esc collapses to primary caret
- Additional carets render via DrawAdditionalCarets in Editor.Drawing.cs
- Tests in EditorMultiCaretTests.cs validate add/remove/track/undo

Agent-Logs-Url: https://github.com/gui-cs/Editor/sessions/7b03aa72-499b-44ed-bed4-ab2c6f1eff89

Co-authored-by: tig <585482+tig@users.noreply.github.com>
Copilot AI changed the title [WIP] Implement multi-caret support with additional caret offsets and selections feat: multi-caret editing (Ctrl+Click, per-caret insert/delete, single-step undo) May 13, 2026
Copilot finished work on behalf of tig May 13, 2026 14:37
Copilot AI requested a review from tig May 13, 2026 14:37
@tig tig marked this pull request as ready for review May 13, 2026 14:49
@tig
Copy link
Copy Markdown
Member

tig commented May 13, 2026

@copilot See the consitituion and make sure you are following it (you are not).

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7467d18e80

ℹ️ 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".

Comment thread src/Terminal.Gui.Editor/Editor.MultiCaret.cs
Comment thread src/Terminal.Gui.Editor/Editor.MultiCaret.cs Outdated
…ief), R9 (ted wiring)

- Move additional-caret rendering from direct draw to MultiCaretRenderer : IBackgroundRenderer (R1)
- Use AddRune instead of ch.ToString() for proper cell-based rendering (R2)
- Add HasMultipleCarets/ToggleCaretAt/ClearAdditionalCarets to specs/public-api.md (R8)
- Wire multi-caret indicator in ted status bar so feature is exercisable (R9)

Agent-Logs-Url: https://github.com/gui-cs/Editor/sessions/94cce0e0-db7a-4e71-a5d4-690767b08be7

Co-authored-by: tig <585482+tig@users.noreply.github.com>
@chatgpt-codex-connector
Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Credits must be used to enable repository wide code reviews.

Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 13, 2026

@copilot See the consitituion and make sure you are following it (you are not).

Fixed in a4f97bd. The violations were:

  • R1: Was drawing additional carets directly in the draw pipeline. Moved to MultiCaretRenderer : IBackgroundRenderer.
  • R2: Was using ch.ToString() per char. Now uses AddRune(new Rune(...)).
  • R8: Added HasMultipleCarets, ToggleCaretAt, ClearAdditionalCarets to specs/public-api.md.
  • R9: Wired multi-caret into ted — status bar shows caret count when in multi-caret mode, so the feature is exercisable by a customer via the demo app.

Copilot finished work on behalf of tig May 13, 2026 14:56
@tig
Copy link
Copy Markdown
Member

tig commented May 13, 2026

@copilot see CR feedback. Ensure there's a test that proves the CR feedback (or not) and then fix.

…art indent delete

CR feedback addressed:
- MultiCaretNewLine now applies IndentationStrategy.IndentLine after inserting
  newline at each caret, matching single-caret InsertNewLineWithAutoIndent behavior.
- MultiCaretDeleteLeft now calls TryDeleteIndentationLeftAt to delete a full
  indentation unit when the caret is at a leading-whitespace boundary, matching
  single-caret smart-backspace behavior.
- Extracted TryDeleteIndentationLeftAt(offset) from TryDeleteIndentationLeft() to
  support arbitrary offset (used by both single- and multi-caret paths).
- Added two tests proving both behaviors.

Agent-Logs-Url: https://github.com/gui-cs/Editor/sessions/76ee9161-1be5-473a-a215-8dcda238a093

Co-authored-by: tig <585482+tig@users.noreply.github.com>
@chatgpt-codex-connector
Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Credits must be used to enable repository wide code reviews.

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Credits must be used to enable repository wide code reviews.

Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 13, 2026

@copilot see CR feedback. Ensure there's a test that proves the CR feedback (or not) and then fix.

Fixed in 62a99f1 and 7d003d9. Both CR issues addressed:

  1. Multi-caret Enter now applies IndentationStrategy.IndentLine after each newline insertion, matching InsertNewLineWithAutoIndent behavior.
  2. Multi-caret Backspace now calls TryDeleteIndentationLeftAt(offset) before falling back to single-char removal, matching single-caret smart-backspace behavior.

Extracted TryDeleteIndentationLeftAt(int offset) from TryDeleteIndentationLeft() so both single- and multi-caret paths share the same logic.

Two new tests exercise the actual Command.NewLine and Command.DeleteCharLeft paths via InvokeCommand with multiple carets active, proving both fixes work end-to-end.

Copilot finished work on behalf of tig May 13, 2026 15:09
@tig
Copy link
Copy Markdown
Member

tig commented May 13, 2026

@copilot resolve the merge conflicts in this pull request

…caret-support

# Conflicts:
#	src/Terminal.Gui.Editor/Editor.Commands.cs

Co-authored-by: tig <585482+tig@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 13, 2026

@copilot resolve the merge conflicts in this pull request

Resolved in 1fb077a. The conflict was in Editor.Commands.cs where the new clipboard commands (Copy/Cut/Paste from develop) overlapped with the multi-caret editing command wiring. The merge keeps both: clipboard commands first, then multi-caret-aware NewLine/DeleteCharLeft/DeleteCharRight bindings. All 416 tests pass.

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Credits must be used to enable repository wide code reviews.

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Credits must be used to enable repository wide code reviews.

Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 14, 2026

@copilot also see CR feedback

Fixed in 49b0bf7 (with cleanup in e92d447). Both CR feedback items addressed:

  1. P1 – Surrogate pair crash: Extracted GetRuneAt(int offset) helper that checks char.IsHighSurrogate/char.IsLowSurrogate and uses char.ConvertToUtf32 for non-BMP characters, falling back to a space Rune for lone surrogates.

  2. P2 – Word-wrap caret misplacement: Range check now uses the visual line's element bounds (Elements[0].DocumentOffset to Elements[^1].DocumentEndOffset) instead of the full DocumentLine, so carets are only painted on the wrapped segment they belong to.

Copilot finished work on behalf of tig May 14, 2026 04:04
@tig
Copy link
Copy Markdown
Member

tig commented May 14, 2026

@copilot ensure this is documented in the readme. Add a ./examples/ted/docs/multi-caret.md as well (I will be creating a ted feature with a help browser) in a future pr.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0d460ec692

ℹ️ 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".

Comment thread src/Terminal.Gui.Editor/Rendering/MultiCaretRenderer.cs
Comment thread src/Terminal.Gui.Editor/Rendering/MultiCaretRenderer.cs Outdated
Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 14, 2026

@copilot ensure this is documented in the readme. Add a ./examples/ted/docs/multi-caret.md as well (I will be creating a ted feature with a help browser) in a future pr.

Done in 39ee69f. Added a multi-caret bullet to the README Features → Editing section (with a link), and created examples/ted/docs/multi-caret.md covering usage (Ctrl+Click / Escape), editing behavior (typing, Enter, Backspace, Delete), visual feedback, programmatic API, and current limitations.

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Credits must be used to enable repository wide code reviews.

Copilot finished work on behalf of tig May 14, 2026 13:34
@tig
Copy link
Copy Markdown
Member

tig commented May 14, 2026

@copilot see new CR comments. Ensure there are unit tests that fail proving the issue before fixing.

…exclusive segEnd bound

Agent-Logs-Url: https://github.com/gui-cs/Editor/sessions/40e6a456-611c-47a9-ac5d-d849322164fa

Co-authored-by: tig <585482+tig@users.noreply.github.com>
@chatgpt-codex-connector
Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Credits must be used to enable repository wide code reviews.

Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 14, 2026

@copilot see new CR comments. Ensure there are unit tests that fail proving the issue before fixing.

Fixed in 757f1b4. Both CR items addressed:

  1. P1 – Caret overwritten by text: Introduced IOverlayRenderer interface and OverlayRenderers collection. MultiCaretRenderer now implements IOverlayRenderer and draws AFTER elements (not before), ensuring caret cells are never overwritten by subsequent text drawing.

  2. P2 – Duplicate caret at wrap boundary: Changed offset > segEnd to offset >= segEnd since DocumentEndOffset is exclusive. At a wrap boundary, the caret now appears only on the next segment's row.

Two integration tests prove both fixes: MultiCaret_Renders_Inverted_Attribute_On_Text (P1) and MultiCaret_WordWrap_No_Duplicate_At_Boundary (P2). All 564 tests pass.

Copilot finished work on behalf of tig May 14, 2026 13:47
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 20ceab0f67

ℹ️ 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".

Comment thread src/Terminal.Gui.Editor/Rendering/MultiCaretRenderer.cs Outdated
@tig
Copy link
Copy Markdown
Member

tig commented May 14, 2026

@copilot see new CR feedback. ensure there are unit tests that fail proving the issue before fixing it.

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Credits must be used to enable repository wide code reviews.

Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 14, 2026

@copilot see new CR feedback. ensure there are unit tests that fail proving the issue before fixing it.

Fixed in 90323b8. The CR issue was that offset >= segEnd excluded carets at end-of-line positions (where offset == line.EndOffset).

Extracted IsOffsetInSegment(offset, segStart, segEnd, lineEndOffset) as a testable internal static method. The logic: allow offset == segEnd only when segEnd == lineEndOffset (true EOL, not a wrap boundary). This maintains the P2 wrap-boundary duplicate prevention while fixing P2's regression on EOL carets.

7 unit tests (IsOffsetInSegment_Correctly_Filters_Offsets) prove the filtering logic handles all cases — EOL, wrap boundaries, empty lines, and out-of-range offsets.

Copilot finished work on behalf of tig May 14, 2026 14:23
@tig tig merged commit da677a9 into develop May 14, 2026
10 of 11 checks passed
@tig tig deleted the copilot/add-multi-caret-support branch May 14, 2026 19:04
tig added a commit that referenced this pull request May 17, 2026
…rvey

All four beta features (find-and-replace #104, clipboard #107, word-wrap
#106, multi-caret #105) plus vertical-multi-caret #133 and syntax-theme
Phase 2 #134 have merged since the 2026-05-13 plan snapshot. Bring the
spec set back in line with develop:

- Per-feature status lines -> Done with PR/issue refs (clipboard,
  multi-caret, find-and-replace, word-wrap, vertical-multi-caret,
  syntax-theme).
- plan.md rescoped to the beta endgame: new "Done (beta)" table, a
  "Remaining for beta" that reflects no feature work is left (only
  external/verification/cut items), evidence-checked DoD boxes,
  refreshed dependency graph and header.
- decisions.md: OPEN-005 annotated as settled by syntax-theme; add
  OPEN-006 (single-line/input-mode decision).
- codex-autonomous-sprint.md: flag stale work pool.
- New specs/textview-parity-gap/spec.md: survey of TextView
  capabilities Editor lacks (autocomplete, overwrite mode,
  single-line mode, kill-ring, context menu) with dispositions;
  wired into plan.md follow-ups.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

multi-caret: AdditionalCaretOffsets + Ctrl+Click + per-caret selection + single-step undo

2 participants