Skip to content

feat(settings): add opt-in trailing space after accepting a suggestion#675

Merged
FuJacob merged 2 commits into
mainfrom
feat/auto-space-on-accept
Jun 12, 2026
Merged

feat(settings): add opt-in trailing space after accepting a suggestion#675
FuJacob merged 2 commits into
mainfrom
feat/auto-space-on-accept

Conversation

@FuJacob

@FuJacob FuJacob commented Jun 11, 2026

Copy link
Copy Markdown
Owner

Summary

Adds a new opt-in "Add Space After Accepting" toggle (Settings → General → Behavior). When on, accepting a suggestion that finishes a word also types a trailing space so the user can keep typing without reaching for the space bar. This was a requested feature; it's off by default so existing WYSIWYG accept behavior is unchanged unless opted into.

The space is only appended when the accept exhausts the suggestion (the final chunk) — a mid-suggestion word accept is already followed by the next chunk's own leading space, so a space there would double up. Exhaustion is predicted the same way commitAcceptedChunk decides it (session.advancing(by:).isExhausted). The space is suppressed when the inserted text ends in punctuation (done., (yes), really?!), whitespace, or a space-less script (CJK/Thai never separate words with spaces), reusing the existing isAcceptanceWordCharacter / beginsSpacelessScriptWord primitives. Session accounting still advances by the unchanged acceptedChunk, and the session tears down on exhaustion, so the extra space never disturbs consumed-suffix reconciliation.

Validation

xcodebuild -project Cotabby.xcodeproj -scheme Cotabby -destination 'platform=macOS' build -derivedDataPath build/DerivedData
# ** BUILD SUCCEEDED **

xcodebuild ... test -only-testing:CotabbyTests/SuggestionSessionReconcilerTests CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO
# ** TEST SUCCEEDED **  93 tests, 0 failures (includes 6 new tests for the pure helper)

xcodebuild ... test -only-testing:CotabbyTests/SettingsIndexTests -only-testing:CotabbyTests/SuggestionCoordinatorAcceptanceTests CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO
# ** TEST SUCCEEDED **

swiftlint lint --quiet  # on all changed files, exit 0

Pure rule lives in SuggestionSessionReconciler.insertionChunkAppendingTrailingSpace(_:) (Support/), covered by new unit tests for word/digit/punctuation/whitespace/CJK/empty cases. The coordinator gates it via a small insertionTextApplyingAutoSpace(...) helper (kept separate so acceptSuggestion stays under the cyclomatic-complexity limit).

Linked issues

Risk / rollout notes

  • New persisted setting: UserDefaults key cotabbyAddSpaceAfterAccept, defaults to false, so no behavior change for existing installs until opted in. Threaded through the full settings stack (data → store load/write-back/save → model @Published/setter/snapshot/Combine publisher → snapshot struct → UI toggle → search index).
  • The new Combine upstream is paired with the existing trailing-punctuation toggle inside the timing tuple's last slot to stay under Combine's four-input CombineLatest cap.
  • No project.yml/pbxproj changes (new test code is auto-discovered by folder).

Greptile Summary

This PR adds an opt-in "Add Space After Accepting" toggle in Settings → General → Behavior. When enabled, accepting the final chunk of a suggestion appends a trailing space, letting users continue typing without pressing Space. The setting defaults to false so no behavior change occurs for existing installs.

  • The pure suppression rule lives in SuggestionSessionReconciler.insertionChunkAppendingTrailingSpace, which skips the space for text ending in punctuation, whitespace, or a spaceless-script (CJK/Thai) glyph; 6 new unit tests cover every branch.
  • Exhaustion is predicted with session.advancing(by: acceptedChunk.count).isExhausted before commitAcceptedChunk, matching the same logic, so a mid-suggestion accept (where the next chunk already carries a leading space) never receives a doubled space. Session accounting still advances by the unmodified acceptedChunk, keeping consumed-suffix reconciliation intact.

Confidence Score: 5/5

Safe to merge — the feature is off by default, exhaustion prediction uses the same advancing logic as the actual commit, and suppression guards (punctuation, whitespace, CJK) are fully unit-tested.

The acceptance coordinator carefully predicts exhaustion before inserting so the space is never appended to a mid-suggestion chunk, and session accounting still advances by the unmodified acceptedChunk, keeping consumed-suffix reconciliation intact. The new setting is opt-in with a false default, so existing installs see no change. The pure helper function is isolated in SuggestionSessionReconciler with comprehensive unit tests, and the Combine publisher nesting to stay within the four-input cap follows the established codebase pattern.

No files require special attention.

Important Files Changed

Filename Overview
Cotabby/App/Coordinators/SuggestionCoordinator+Acceptance.swift Adds insertionTextApplyingAutoSpace helper before insertion; exhaustion prediction matches commitAcceptedChunk logic; presentAdvancedOverlay correctly keeps using insertionChunk (only reachable when not exhausted, so insertionText == insertionChunk there).
Cotabby/Support/SuggestionSessionReconciler.swift New pure static method insertionChunkAppendingTrailingSpace correctly suppresses trailing space for empty chunks, punctuation, whitespace, and CJK/spaceless-script glyphs using existing isAcceptanceWordCharacter / beginsSpacelessScriptWord primitives.
Cotabby/Models/SuggestionSettingsModel.swift Adds addSpaceAfterAccept @published property, threads it through the snapshot builder, and pairs it with autoAcceptTrailingPunctuation in a nested CombineLatest to stay within Combine's four-input cap — pattern is consistent with other recently added toggles.
Cotabby/Support/SuggestionSettingsStore.swift New UserDefaults key cotabbyAddSpaceAfterAccept with explicit false default; load, save, and write-back all wired correctly following the existing pattern.
Cotabby/UI/Settings/Panes/GeneralPaneView.swift Toggle and Binding added correctly; description text is accurate for the punctuation/whitespace suppression case.
Cotabby/UI/Settings/SettingsIndex.swift New addSpaceAfterAccept case correctly categorised as .general, icon matches the toggle in GeneralPaneView, and search keywords are comprehensive.
CotabbyTests/SuggestionSessionReconcilerTests.swift Six new unit tests cover: word suffix, digit suffix, punctuation endings, existing trailing whitespace, CJK/spaceless-script, and empty string — all meaningful branches of the new function.
Cotabby/Models/SuggestionEngineModels.swift addSpaceAfterAccept field added to SuggestionSettingsSnapshot with a clear doc comment; struct remains Equatable and Sendable.
Cotabby/Models/SuggestionSettingsData.swift addSpaceAfterAccept var added to SuggestionSettingsData with a clear doc comment explaining the opt-in default.
CotabbyTests/CotabbyTestFixtures.swift Default parameter addSpaceAfterAccept: Bool = false added to the snapshot fixture factory, consistent with the production default.

Sequence Diagram

sequenceDiagram
    participant U as User (Tab key)
    participant SC as SuggestionCoordinator
    participant R as SuggestionSessionReconciler
    participant SI as SuggestionInserter
    participant S as ActiveSuggestionSession

    U->>SC: acceptSuggestion()
    SC->>R: insertionChunk(forAcceptedChunk:precedingText:)
    R-->>SC: insertionChunk (leading-space stripped if needed)
    SC->>S: advancing(by: acceptedChunk.count).isExhausted
    S-->>SC: isExhausted (exhaustion prediction)
    alt addSpaceAfterAccept ON AND session exhausted
        SC->>R: insertionChunkAppendingTrailingSpace(insertionChunk)
        R-->>SC: insertionText (+ trailing space if word char, non-CJK)
    else setting OFF or not exhausted
        SC-->>SC: "insertionText = insertionChunk"
    end
    SC->>SI: insert(insertionText)
    SI-->>SC: success / failure
    SC->>S: commitAcceptedChunk(acceptedChunk)
    alt exhausted
        S-->>SC: .exhausted
        SC->>SC: hideOverlay, armPostExhaustionAcceptance, schedulePrediction
    else advanced
        S-->>SC: .advanced(session)
        SC->>SC: presentAdvancedOverlay(insertionChunk)
    end
Loading

Reviews (2): Last reviewed commit: "Merge remote-tracking branch 'origin/mai..." | Re-trigger Greptile

When the user enables "Add Space After Accepting", an accept that finishes a
word and exhausts the suggestion also types a trailing space so they can keep
typing without reaching for the space bar. The space is gated on exhaustion
(only the final chunk; a mid-suggestion accept already gets the next chunk's
own leading space) and suppressed after punctuation, whitespace, or a
space-less script. Defaults off so the WYSIWYG accept behavior is unchanged
unless opted into.
Comment on lines +77 to +78
description: "When accepting a suggestion finishes a word, also add a space so you can " +
"keep typing. Skipped when it already ends in punctuation or a space.",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 The description mentions punctuation and space as suppression cases but omits spaceless scripts (CJK, Thai, etc.). A user who writes in Japanese and enables this toggle will notice no space ever appears — the description as written doesn't tell them why. A small addition like "or in a language that doesn't use spaces (e.g. Chinese, Japanese)" would set the right expectation.

Suggested change
description: "When accepting a suggestion finishes a word, also add a space so you can " +
"keep typing. Skipped when it already ends in punctuation or a space.",
description: "When accepting a suggestion finishes a word, also add a space so you can " +
"keep typing. Skipped when it already ends in punctuation, a space, or a language " +
"that doesn't use spaces (e.g. Chinese, Japanese).",

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Fix in Codex Fix in Claude Code

# Conflicts:
#	Cotabby/App/Coordinators/SuggestionCoordinator+Acceptance.swift
@FuJacob FuJacob merged commit 9541f1e into main Jun 12, 2026
4 checks passed
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