Skip to content

Add braille text wrap modes with continuation marks#20146

Merged
seanbudd merged 8 commits into
nvaccess:masterfrom
LeonarddeR:braille-textwrap-refactor
May 20, 2026
Merged

Add braille text wrap modes with continuation marks#20146
seanbudd merged 8 commits into
nvaccess:masterfrom
LeonarddeR:braille-textwrap-refactor

Conversation

@LeonarddeR
Copy link
Copy Markdown
Collaborator

@LeonarddeR LeonarddeR commented May 16, 2026

Link to issue number:

Part of #17010. Split out from #19916 at reviewer request — this is the second of three PRs. The pyphen abstraction layer was shipped in #20145; the syllable-aware wrap mode follows in a separate PR.

Summary of the issue:

The braille word-wrap setting is a single boolean that gives users no control over how words are broken at the display edge. When a word is cut mid-way there is also no visual indication that the word continues on the next row.

Description of user facing changes:

The boolean "word wrap" checkbox in the braille settings has been replaced with a Text wrap combo box with three choices:

  • Off — Wrap at the raw edge of the display, cutting words in the middle if necessary. No visual indication that a word was cut.
  • Show mark when words are cut — Wrap at the raw edge, but whenever a word is cut mid-way, replace the last cell of the row with a continuation mark (braille dots 7-8) so the reader knows the word continues on the next row.
  • At word boundaries — Prefer breaking at spaces. If no space fits on the row, fall back to cutting the word and showing the continuation mark.

Existing config profiles with the old setting are automatically upgraded.

Description of developer facing changes:

  • BrailleTextWrapFlag feature flag enum added to config.featureFlagEnums with members DEFAULT, NONE, MARK_WORD_CUTS, AT_WORD_BOUNDARIES.
  • Config schema bumped v22 → v23; old wordWrap boolean is deprecated and bridged bidirectionally to textWrap via _linkDeprecatedValues, so add-ons reading or writing the old key keep working (with a deprecation warning).
  • CONTINUATION_SHAPE = 0xC0 (dots 7-8) constant added to braille.
  • _WindowRowPositions frozen dataclass added to braille to hold the start/end buffer positions and continuation-mark flag for each row of the braille window, replacing the previous anonymous tuple.

Description of development approach:

The continuation mark is unified: it consistently means "a word was cut here" regardless of mode, so readers get a predictable signal.

BrailleBuffer._calculateWindowRowBufferOffsets is extended to implement all three modes. Each entry in _windowRowBufferOffsets is a _WindowRowPositions instance whose showContinuationMark field records whether that row needs a continuation mark. BrailleBuffer._get_windowBrailleCells reads that flag to insert the mark. BrailleBuffer._set_windowEndPos short-circuits space-seeking for NONE and MARK_WORD_CUTS modes (backwards scroll alignment).

Testing strategy:

Unit tests cover:

  • All three wrap modes and their edge cases in _calculateWindowRowBufferOffsets (no cells, fits exactly, word cut, word too long for display, no space on line).
  • Continuation-mark rendering in _get_windowBrailleCells.
  • Profile upgrade from wordWrap = True/False → correct textWrap flag values.

Manual testing: loaded a pre-upgrade profile with wordWrap = True/False and confirmed the upgrade writes the expected textWrap value and the braille settings panel shows the matching label.

Known issues with pull request:

None.

Code Review Checklist:

  • Documentation:
    • Change log entry
    • User Documentation
    • Developer / Technical Documentation
    • Context sensitive help for GUI changes
  • Testing:
    • Unit tests
    • System (end to end) tests
    • Manual testing
  • UX of all users considered:
    • Speech
    • Braille
    • Low Vision
    • Different web browsers
    • Localization in other languages / culture than English
  • API is compatible with existing add-ons.
  • Security precautions taken.

@LeonarddeR LeonarddeR mentioned this pull request May 16, 2026
12 tasks
@LeonarddeR LeonarddeR force-pushed the braille-textwrap-refactor branch 2 times, most recently from f040151 to e080142 Compare May 16, 2026 08:09
@seanbudd seanbudd added the conceptApproved Similar 'triaged' for issues, PR accepted in theory, implementation needs review. label May 18, 2026
Replaces boolean wordWrap config with BrailleTextWrapFlag feature flag
(NONE, MARK_WORD_CUTS, AT_WORD_BOUNDARIES, AT_WORD_OR_SYLLABLE_BOUNDARIES).
Adds profile upgrade step v22->v23, deprecated API bridge, GUI combo box,
continuation mark (dots 7-8) when a word is cut mid-display, and
_continuationRows tracking in BrailleBuffer. Syllable boundary mode
is wired but its backend follows in a separate PR.
@LeonarddeR LeonarddeR force-pushed the braille-textwrap-refactor branch from e080142 to 2ac4ae4 Compare May 19, 2026 07:22
_continuationRows was a parallel list kept in sync with
_windowRowBufferOffsets and joined by index at read time.
Merge into list[tuple[int, int, bool]] to eliminate the
sync burden and O(n) membership test.

Also: extract _isMidWordCut helper (removes duplication),
drop dead guard `end - start == numCols` (always true in
that branch), fix redundant rindex call (second search
[start, end) finds same index as first over [start, end+1)
when lastSpaceIndex < end), delete stale wordWrap key in
upgrade step 22→23 (matches pattern of all other renames).
@LeonarddeR LeonarddeR marked this pull request as ready for review May 19, 2026 08:26
@LeonarddeR LeonarddeR requested a review from a team as a code owner May 19, 2026 08:26
Copilot AI review requested due to automatic review settings May 19, 2026 08:26
@LeonarddeR LeonarddeR requested a review from a team as a code owner May 19, 2026 08:26
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Replaces the boolean wordWrap braille setting with a three-valued textWrap feature flag (Off / Show mark when words are cut / At word boundaries), and introduces a continuation marker (dots 7-8) shown in the last cell of a row when a word is cut across rows.

Changes:

  • New BrailleTextWrapFlag feature flag enum, settings dialog combo box, and updated _calculateWindowRowBufferOffsets / _get_windowBrailleCells logic to emit a continuation shape on cut rows.
  • Config schema bumped to version 23 with a profile upgrade step migrating wordWraptextWrap, and a deprecated-key link from wordWrap to textWrap.
  • Updated user docs/changelog and added/updated unit tests.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
source/config/featureFlagEnums.py Adds BrailleTextWrapFlag enum with display strings.
source/config/configSpec.py Bumps schema to 23, marks wordWrap deprecated, adds textWrap.
source/config/profileUpgradeSteps.py Adds upgrade step 22→23 migrating wordWrap to textWrap.
source/config/init.py Re-enables _linkDeprecatedValues and bridges wordWraptextWrap.
source/braille.py Adds CONTINUATION_SHAPE, mid-word cut handling, continuation flag in row offsets.
source/gui/settingsDialogs.py Replaces word-wrap checkbox with a FeatureFlagCombo.
tests/unit/test_braille/test_calculateWindowRowBufferOffsets.py Updates and extends tests for new wrap flag behavior.
tests/unit/test_braille/test_windowBrailleCells.py New tests for continuation cell injection in window cells.
user_docs/en/userGuide.md Documents the new Text wrap combo and modes.
user_docs/en/changes.md Notes the new feature and deprecation.

Comment thread source/config/__init__.py
Comment thread source/config/profileUpgradeSteps.py Outdated
Comment thread source/braille.py
Comment thread source/braille.py
'word or syllable boundaries' was inaccurate; BrailleTextWrapFlag has no
syllable option. Correct to 'at word boundaries'.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Comment thread source/config/featureFlagEnums.py Outdated
Comment thread source/gui/settingsDialogs.py
Comment thread source/braille.py Outdated
@LeonarddeR LeonarddeR requested a review from Copilot May 20, 2026 05:38
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 6 comments.

Comment thread source/config/profileUpgradeSteps.py
Comment thread source/braille.py
Comment thread user_docs/en/userGuide.md
Comment thread user_docs/en/changes.md Outdated
Comment thread source/braille.py
Comment thread tests/unit/test_braille/test_calculateWindowRowBufferOffsets.py Outdated
LeonarddeR and others added 2 commits May 20, 2026 07:48
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Member

@Qchristensen Qchristensen left a comment

Choose a reason for hiding this comment

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

Reads well

@seanbudd seanbudd merged commit c84a8cd into nvaccess:master May 20, 2026
39 of 42 checks passed
@github-actions github-actions Bot added this to the 2026.3 milestone May 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

conceptApproved Similar 'triaged' for issues, PR accepted in theory, implementation needs review.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants