Skip to content

Commit dc7eb28

Browse files
authored
Improve Paragraph Navigation - add single and multi line break style (#13798)
Closes #13797 Summary of the issue: Not all applications support navigating by paragraph (control + up/down arrow) natively. A specific example is web browsers. Description of how this pull request fixes the issue: Add "Document Navigation" settings panel allowing explicit choice of strategy for navigating by paragraph: Handled by application (default): No change in behavior. The application is responsible for responding to the key press. Single line break: Use a single end of line character to define a paragraph boundary. Multi line break: Use two or more end of line characters (I.E. at least one blank line) to define a paragraph boundary. Fallback to "Handled by application" when single line break or double line break fails. Description of changes for the user: Paragraph navigation is now supported in editors, such as Notepad and Notepad++, which do not support this feature natively. For editors which already support paragraph navigation, such as WordPad, block style paragraphs (those separated by one or more blank lines) may now be navigated in addition to single line break paragraphs. When selecting the default option, Handled by application, paragraph navigation performs exactly as it did before this feature was added.
1 parent 28d8aa5 commit dc7eb28

File tree

12 files changed

+863
-17
lines changed

12 files changed

+863
-17
lines changed

source/config/configSpec.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# -*- coding: UTF-8 -*-
22
# A part of NonVisual Desktop Access (NVDA)
33
# Copyright (C) 2006-2022 NV Access Limited, Babbage B.V., Davy Kager, Bill Dengler, Julien Cochuyt,
4-
# Joseph Lee, Dawid Pieper, mltony, Bram Duvigneau, Cyrille Bougot
4+
# Joseph Lee, Dawid Pieper, mltony, Bram Duvigneau, Cyrille Bougot, Rob Meredith
55
# This file is covered by the GNU General Public License.
66
# See the file COPYING for more details.
77

@@ -225,6 +225,9 @@
225225
reportFrames = boolean(default=true)
226226
reportClickable = boolean(default=true)
227227
228+
[documentNavigation]
229+
paragraphStyle = featureFlag(optionsEnum="ParagraphNavigationFlag", behaviorOfDefault="application")
230+
228231
[reviewCursor]
229232
simpleReviewMode = boolean(default=True)
230233
followFocus = boolean(default=True)

source/config/featureFlagEnums.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# A part of NonVisual Desktop Access (NVDA)
2-
# Copyright (C) 2022 NV Access Limited, Bill Dengler
2+
# Copyright (C) 2022 NV Access Limited, Bill Dengler, Rob Meredith
33
# This file is covered by the GNU General Public License.
44
# See the file COPYING for more details.
55

@@ -67,6 +67,24 @@ def __bool__(self):
6767
return self == BoolFlag.ENABLED
6868

6969

70+
class ParagraphNavigationFlag(DisplayStringEnum):
71+
@property
72+
def _displayStringLabels(self):
73+
return {
74+
# Translators: Label for a paragraph style in NVDA settings.
75+
self.APPLICATION: _("Handled by application"),
76+
# Translators: Label for a paragraph style in NVDA settings.
77+
self.SINGLE_LINE_BREAK: _("Single line break"),
78+
# Translators: Label for a paragraph style in NVDA settings.
79+
self.MULTI_LINE_BREAK: _("Multi line break")
80+
}
81+
82+
DEFAULT = enum.auto()
83+
APPLICATION = enum.auto()
84+
SINGLE_LINE_BREAK = enum.auto()
85+
MULTI_LINE_BREAK = enum.auto()
86+
87+
7088
class WindowsTerminalStrategyFlag(DisplayStringEnum):
7189
"""
7290
A feature flag for defining how new text is calculated in Windows Terminal

source/cursorManager.py

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
#cursorManager.py
2-
#A part of NonVisual Desktop Access (NVDA)
3-
#Copyright (C) 2006-2018 NV Access Limited, Joseph Lee, Derek Riemer, Davy Kager
4-
#This file is covered by the GNU General Public License.
5-
#See the file COPYING for more details.
1+
# A part of NonVisual Desktop Access (NVDA)
2+
# Copyright (C) 2006-2022 NV Access Limited, Joseph Lee, Derek Riemer, Davy Kager, Rob Meredith
3+
# This file is covered by the GNU General Public License.
4+
# See the file COPYING for more details.
65

76
"""
87
Implementation of cursor managers.
@@ -26,9 +25,13 @@
2625
import braille
2726
import vision
2827
import controlTypes
29-
from inputCore import SCRCAT_BROWSEMODE
28+
from inputCore import (
29+
SCRCAT_BROWSEMODE,
30+
InputGesture,
31+
)
3032
import ui
3133
from textInfos import DocumentWithPageTurns
34+
from logHandler import log
3235

3336

3437
class FindDialog(
@@ -264,12 +267,35 @@ def script_moveBySentence_forward(self,gesture):
264267
self._caretMovementScriptHelper(gesture,textInfos.UNIT_SENTENCE,1)
265268
script_moveBySentence_forward.resumeSayAllMode = sayAll.CURSOR.CARET
266269

267-
def script_moveByParagraph_back(self,gesture):
268-
self._caretMovementScriptHelper(gesture,textInfos.UNIT_PARAGRAPH,-1)
270+
def _handleParagraphNavigation(self, gesture: InputGesture, nextParagraph: bool) -> None:
271+
from config.featureFlagEnums import ParagraphNavigationFlag
272+
flag: config.featureFlag.FeatureFlag = config.conf["documentNavigation"]["paragraphStyle"]
273+
if (
274+
flag.calculated() == ParagraphNavigationFlag.APPLICATION
275+
or flag.calculated() == ParagraphNavigationFlag.SINGLE_LINE_BREAK
276+
):
277+
self._caretMovementScriptHelper(gesture, textInfos.UNIT_PARAGRAPH, 1 if nextParagraph else -1)
278+
elif flag.calculated() == ParagraphNavigationFlag.MULTI_LINE_BREAK:
279+
from documentNavigation.paragraphHelper import moveToMultiLineBreakParagraph
280+
ti = self.makeTextInfo(textInfos.POSITION_SELECTION)
281+
passKey, moved = moveToMultiLineBreakParagraph(
282+
nextParagraph=nextParagraph,
283+
speakNew=not willSayAllResume(gesture),
284+
ti=ti)
285+
if moved:
286+
self.selection = ti
287+
elif passKey:
288+
# fail over to default behavior
289+
self._caretMovementScriptHelper(gesture, textInfos.UNIT_PARAGRAPH, 1 if nextParagraph else -1)
290+
else:
291+
log.error(f"Unexpected ParagraphNavigationFlag value {flag.value}")
292+
293+
def script_moveByParagraph_back(self, gesture: InputGesture):
294+
self._handleParagraphNavigation(gesture, False)
269295
script_moveByParagraph_back.resumeSayAllMode = sayAll.CURSOR.CARET
270296

271-
def script_moveByParagraph_forward(self,gesture):
272-
self._caretMovementScriptHelper(gesture,textInfos.UNIT_PARAGRAPH,1)
297+
def script_moveByParagraph_forward(self, gesture: InputGesture):
298+
self._handleParagraphNavigation(gesture, True)
273299
script_moveByParagraph_forward.resumeSayAllMode = sayAll.CURSOR.CARET
274300

275301
def script_startOfLine(self,gesture):

0 commit comments

Comments
 (0)