Skip to content

NVDA 2026.1 compatibility + build system modernization (v1.9.0) - #47

Merged
marlon-sousa merged 1 commit into
masterfrom
feat/nvda-2026.1-compatibility
Jul 14, 2026
Merged

NVDA 2026.1 compatibility + build system modernization (v1.9.0)#47
marlon-sousa merged 1 commit into
masterfrom
feat/nvda-2026.1-compatibility

Conversation

@marlon-sousa

@marlon-sousa marlon-sousa commented Jul 12, 2026

Copy link
Copy Markdown
Owner

Summary

Makes EnhancedFindDialog compatible with NVDA 2026.1 and modernizes the build system by porting TimerForNVDA's tooling. NVDA 2026.1 bumped its addon API BACK_COMPAT_TO to (2026, 1, 0) (Python 3.11→3.13, 32→64-bit), which disabled this addon on manifest metadata alone. A full audit against the 2026.1 source found no breaking API change beyond the gui.messageBox deprecation.

Release version 1.9.0. Minimum/last-tested NVDA is now 2026.1 — no cross-version compatibility code.

Code changes (addon/globalPlugins/EnhancedFindDialog/)

  • Migrate gui.messageBoxgui.message.MessageDialog.alert at all three call sites (not-found, invalid regexp, unsupported-backend). This also fixes a pre-existing crash: the "backend does not support regexp" path previously called a string as if it were gui.messageBox.
  • Remove the dead version gate in cursorManagerHelper.py (buildVersion.version_year > 2023 is always true now); drop import buildVersion.
  • Replace the custom config-profile machinery with shouldSuspendConfigProfileTriggers. Since 2026.1 is now the floor, the dialog sets shouldSuspendConfigProfileTriggers = True, so NVDA keeps the document's active configuration profile active while the dialog is shown. The dialog now reads/writes config.conf directly (correct profile + automatic dirty-marking/persistence). This removes:
    • the config.ConfigManager.getActiveProfile monkey-patch,
    • capturing/passing the active profile into the dialog,
    • getConfig/setConfig/getDefaultConfig/strToBool/scheduleProfileSave + _dirtyProfiles bookkeeping,
    • the _mustSaveProfile/onStatChange dirty tracking.
      Reading via config.conf also restores native profile-stack fallthrough and spec-validated bools.
  • Removed WIP/scratch files (addon/installTasks.py, a.txt).

Build system modernization (ported from TimerForNVDA)

  • New site_scons/site_tools/NVDATool/ (typed SCons machinery), updated gettexttool, modern sconstruct (EnsurePythonVersion(3, 10), major.minor.patch validation).
  • buildVars.py rewritten in typed AddonInfo form: addon_version=1.9.0, minimumNVDAVersion=2026.1, lastTestedNVDAVersion=2026.1.0, MIT license fields, changelog filled.
  • Manifest templates gain a changelog line.
  • Workflows: replaced the 3 legacy ones with validate.yml (reusable), pr-checks.yml (artifact comment), and release.yml (tag on master → GitHub release). Add-on Store submission is done manually, not from CI.
  • Lint: flake8 4.0.17.1.1 (old pin crashes on Python 3.13), spaces-era flake8.ini, .gitignore additions.

Docs & repo hygiene

  • Contributing docs (root + all localized contributing.md): ported the gettext dependency guidance from EnhancedDictionaries PR Update the pipeline to generate the English README.md correctly. #22 (explains msgfmt and xgettext, recommends a modern Windows gettext build, warns against the frozen GnuWin32 0.14.4 that breaks scons pot) and bumped the stated Python to 3.13. Italian translated to match; other languages reuse the EnhancedDictionaries translations.
  • Stopped tracking the lone generated addon/doc/en/contributing.html (*.html is gitignored; doc HTML is a scons build artifact, matching TimerForNVDA — no generated HTML is version-controlled).

Add-on Store submission

  • Submission to the NVDA Add-on Store is done manually after each release — NV Access does not want automated issue-form submissions from CI, so release.yml stops at creating the GitHub release.

Verification done

  • pre-commit run --all-files — passes (flake8 clean).
  • scons builds EnhancedFindDialog-1.9.0.nvda-addon; scons pot builds the .pot. Bundle manifest confirmed: version=1.9.0, minimumNVDAVersion=2026.1, lastTestedNVDAVersion=2026.1.0, changelog present.

Functional test script (NVDA 2026.1)

This is a manual functional test procedure. The addon patches NVDA's live CursorManager / OffsetsTextInfo inside a running NVDA process, so there is no unit-testable surface — behaviour must be exercised in NVDA itself.

No test fixture ships with the addon. Run the cases below against any long, text-rich web page in browse mode — e.g. a Wikipedia article (https://en.wikipedia.org/wiki/NonVisual_Desktop_Access) or a Google results page. Pick your own search terms from the page as each case instructs; the important thing is the behaviour, not the exact word. Check the NVDA log (see §0) throughout.

0. Environment & setup

  1. NVDA 2026.1 installed (or a 2026.1 source copy).
  2. Build: scons produces EnhancedFindDialog-1.9.0.nvda-addon. Confirm the bundle manifest: version = 1.9.0, minimumNVDAVersion = 2026.1, lastTestedNVDAVersion = 2026.1.0, changelog present.
  3. Install the bundle and restart NVDA (or localdeploy.bat for a source copy).
  4. Set NVDA log level to Debug (Settings → General → Logging level). Review with NVDA+F1.
  5. Open a long, text-rich page in Firefox or Chrome and enter browse mode.

Pass condition for load (do first): after restart, the log shows the add-on loaded with no errors and no DeprecationWarning from gui.messageBox; NVDA+Ctrl+F is bound to the enhanced dialog.

Choosing terms: skim the page and note — a common word (WORD) that appears many times; a word visible only near the top (TOPWORD); a word in mixed casing; a nonsense string that appears nowhere (e.g. qqzztop-absent).

1. Dialog opens with all enhanced controls

Press NVDA+Ctrl+F. Expect the dialog with, in order: combo box ("Type the text you wish to find") holding history, "Search type:" radio (Normal / Regular Expression), "Case sensitive" checkbox, "Search wrap" checkbox, OK/Cancel. Escape closes without searching.

2. Normal search — forward & backward

Caret at top; Normal, Case off, Wrap off. NVDA+Ctrl+F, type WORD, Enter; then NVDA+F3 repeatedly; then NVDA+Shift+F3. Expect: first match reads the whole line (context reading, not just from the match onward); F3 advances through occurrences; Shift+F3 walks back.

3. Search history combo

After §2, NVDA+Ctrl+F, Down/Up in the combo. Expect previously searched terms, most-recent first, most recent pre-selected; selecting + Enter searches it; typing a new term still works.

4. Case sensitivity (persisted per profile)

Pick a term with more than one casing. Search lowercase with Case sensitive unchecked (matches every casing), then checked (matches only exact case). Re-opening the dialog shows the checkbox in its last-saved state.

5. Search wrap + wrap beep (forward)

Caret at bottom (Ctrl+End). NVDA+Ctrl+F, check Search wrap, type TOPWORD, Enter. Expect: wraps to top, short beep (440 Hz), lands on TOPWORD. Without wrap, the same search shows the "0 matches" alert.

6. Single-occurrence wrap (whole-document match path)

Pick a term occurring exactly once; search it, keep the caret at/after it, keep Search wrap checked, search again. Expect: the only occurrence is at the caret; the addon still detects it via the whole-story path, beeps, and keeps the selection (no false "not found").

7. Not-found alert ("0 matches" title)

Wrap off. NVDA+Ctrl+F, type qqzztop-absent, Enter. Expect a MessageDialog alert titled "0 matches", body text "qqzztop-absent" not found. Must be a MessageDialog, not gui.messageBox — confirm no DeprecationWarning logged.

8. Regexp search — forward & backward

Caret at top. Select Regular Expression Search; try patterns matching page content, e.g. \b\w{7,}\b, \d{4}, [A-Z][a-z]+, https?://\S+. NVDA+F3 / NVDA+Shift+F3 walk matches forward/back. Note: with regexp selected, the Case sensitive checkbox is disabled — verify it greys out.

9. Invalid regexp alert

Regexp selected. Type an invalid pattern like [unclosed(, Enter. Expect a MessageDialog alert titled "0 matches", body "The entered text is not a valid regular expression." The dialog does not close/search. (Covers the onOk re.compile guard.)

10. Regexp disabled on unsupported backend

Focus a control whose TextInfo is not an OffsetsTextInfo (e.g. an MS Word document). NVDA+Ctrl+F. Expect the "Search type:" radio disabled and forced to Normal; history shows only "normal" entries.

11. Previously-crashing "backend does not support regexp" path

First do a regexp search on a web page (so the most-recent history entry is a regexp term). Then focus a non-OffsetsTextInfo control (Word) without opening the dialog, and press NVDA+F3. Historically this called a string as gui.messageBox and crashed; it must now show a MessageDialog alert titled "0 matches", body "current textInfo backend does not support regular expression searches" — no traceback. (script_findNext/Previous first re-route to the dialog; the alert in cursorManagerHelper.find is the backstop — confirm no crash either way.)

12. Per-profile persistence — manual profile

Create/activate a manual configuration profile. With it active, set Case sensitive = on, Search wrap = on, search. Switch to default, open dialog. Re-activate manual, open dialog. Expect states saved against the active profile: manual keeps on/on; default keeps its own independent values; survives close/reopen and profile switches.

13. Per-profile persistence — triggered profile (shouldSuspendConfigProfileTriggers)

This is the case that specifically exercises the profile-trigger machinery. The addon no longer captures the active profile itself; it relies on NVDA 2026.1 suspending profile triggers while the dialog (which sets shouldSuspendConfigProfileTriggers = True) is shown. A manual profile (case 12) stays active regardless of focus, so it does not test this — a triggered profile does, because opening the dialog moves focus off the document.

  • Pre: Create an application-specific profile: Configuration profiles → New → "Use this profile for: Current application" while a browser is focused. It activates only while that app has focus (a trigger).
  • Steps: (1) Focused in the browser (app profile triggered/active), open the dialog, set Case sensitive = on and Search wrap = on, search. (2) Move focus to a different app (app profile deactivates), then return to the browser and open the dialog again. (3) Inspect the app-specific profile's .ini under the NVDA user config profiles/ folder, section [EnhancedFindDialog].
  • Expect: step 1 reads/writes the app-specific (triggered) profile — not default (before this refactor, opening the dialog deactivated the triggered profile and silently used the default). Step 2 shows the app profile's own on/on state, independent of default. The [EnhancedFindDialog] section persists in the app-specific .ini (saved on NVDA exit). No profile-switch churn/errors in the log when the dialog opens over the triggered profile.

Regression / log checklist

# Case Result Notes
0 Load: no errors, no gui.messageBox DeprecationWarning
1 Dialog + all controls present
2 Normal fwd/back + context line reading
3 History combo
4 Case sensitivity + persistence
5 Wrap + beep (forward)
6 Single-occurrence wrap path
7 Not-found "0 matches" alert (MessageDialog)
8 Regexp fwd/back
9 Invalid regexp alert (MessageDialog)
10 Regexp radio disabled on non-offsets backend
11 "backend does not support regexp" now shows dialog (no crash)
12 Per-profile persistence — manual profile
13 Per-profile persistence — triggered profile (shouldSuspendConfigProfileTriggers)

Secure mode sanity (optional): on the secure/sign-in screen, NVDA+Ctrl+F falls back to NVDA's built-in Find dialog (the addon disables itself in secure mode). No addon errors logged.

🤖 Generated with Claude Code

@github-actions

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown

NVDA 2026.1 raised its add-on API BACK_COMPAT_TO to (2026, 1, 0)
(Python 3.11->3.13, 32->64-bit), disabling this add-on on manifest
metadata alone. An audit against the 2026.1 source found no breaking API
change beyond the gui.messageBox deprecation. This targets NVDA 2026.1 as
the minimum, with no cross-version compatibility code.

Code (addon/globalPlugins/EnhancedFindDialog/):
- Migrate gui.messageBox -> gui.message.MessageDialog.alert at all three
  call sites. Also fixes a pre-existing crash: the "backend does not
  support regexp" path called a string as if it were gui.messageBox.
- Remove the dead buildVersion.version_year > 2023 gate; drop the import.
- Replace the custom config-profile machinery with
  shouldSuspendConfigProfileTriggers = True on the dialog, so NVDA keeps
  the document's active profile active while the dialog is shown. The
  dialog now reads/writes config.conf directly (correct profile, native
  dirty-marking and persistence). Removes the getActiveProfile
  monkey-patch, the profile capture/passing, getConfig/setConfig/
  strToBool/scheduleProfileSave/_dirtyProfiles, and the _mustSaveProfile/
  onStatChange dirty tracking.
- Remove WIP/scratch files (installTasks.py, a.txt).

Build system (ported from TimerForNVDA):
- site_scons/site_tools/NVDATool typed SCons machinery, updated
  gettexttool, modern sconstruct (EnsurePythonVersion(3, 10),
  major.minor.patch validation).
- buildVars.py rewritten as typed AddonInfo: version 1.9.0,
  minimumNVDAVersion 2026.1, lastTestedNVDAVersion 2026.1.0, MIT license,
  changelog filled. Manifest templates gain a changelog line.
- Workflows: validate.yml (reusable), pr-checks.yml (artifact comment),
  release.yml (tag on master -> GitHub release). Add-on Store submission
  is done manually, not from CI.
- flake8 4.0.1 -> 7.1.1 (old pin crashes on Python 3.13), spaces-era
  flake8.ini, .gitignore additions.

Docs and hygiene:
- Contributing docs (root + localized): gettext guidance (msgfmt +
  xgettext, modern Windows build, avoid frozen GnuWin32 0.14.4) and
  Python 3.13.
- Stop tracking the generated addon/doc/en/contributing.html (*.html is
  gitignored; doc HTML is a scons build artifact).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@marlon-sousa
marlon-sousa force-pushed the feat/nvda-2026.1-compatibility branch from 81ee0d8 to ebe32f6 Compare July 13, 2026 15:04
@github-actions

Copy link
Copy Markdown

@thgcode

thgcode commented Jul 13, 2026

Copy link
Copy Markdown
Collaborator

Performed all tests, all passed.

@marlon-sousa
marlon-sousa merged commit 01b0efd into master Jul 14, 2026
2 checks passed
@marlon-sousa
marlon-sousa deleted the feat/nvda-2026.1-compatibility branch July 14, 2026 10:59
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.

2 participants