Repository: nvaccess/nvda

Issue:
Diff-match-patch: choppy reading in pager output
<!-- Please read the text in this edit field before filling it in.
Please thoroughly read NVDA's wiki article on how to fill in this template, including how to provide the required files.
Issues may be closed if the required information is not present.
https://github.com/nvaccess/nvda/wiki/Github-issue-template-explanation-and-examples
Please also note that the NVDA project has a Citizen and Contributor Code of Conduct which can be found at https://github.com/nvaccess/nvda/blob/master/CODE_OF_CONDUCT.md. NV Access expects that all contributors and other community members read and abide by the rules set out in this document while participating or contributing to this project. This includes creating or commenting on issues and pull requests. 
-->

### Steps to reproduce:
1. Select DMP in advanced preferences.
2. Open cmd.
3. `cd` to the nvda repository.
4. run `git log`.
5. Press space to advance to the next page of output.

### Actual behaviour:
Some common parts of output are omitted, making speech choppy (see below).

### Expected behaviour:
Speech reads all words on the new page.

### Additional context
I collected the text of a `textInfo` created at `POSITION_ALL` before and after pressing space, then manually ran DMP on the two texts. The resulting diff and text indicated for NVDA as changes are as follows (NVDA only reads inserted chunks, tuples with a + as the first element):

#### Changes for NVDA
```python console
>>> [change for change in diff if change[0] == "+"]
[('+', '    readme: briefly mention Nose and Robot and providing them extra arguments via the rununittests and runsystem
tests sc\r\nripts respectively.\r\n\r\ncommit 7eb2584ce47080675bf2a4dffca3bb31946d4f72'), ('+', 'Su'), ('+', '7 17:49:43
'), ('+', 'Update system tests readme to talk about runsystemtests, and not SCons.\r\n\r\ncommit b0cb717278b356151522162
0f68d34581a9482d2'), ('+', '7:3'), ('+', '7'), ('+', 'A'), ('+', ' now'), ('+', 's runlint, rununittests and runsystemte
sts rather than using its own code.\r\n\r\ncommit ed432bf2ac83d0dd0cf1579b179da7e1ece10207'), ('+', 'Thu'), ('+', '4'),
('+', '3:40'), ('+', 'Remove targets for unit tests, system tests and linting from SCons as they all now have their own
run* commands in t\r\nhe root of the repository which are much faster to execute.')]
```

#### Full diff
```python console
>>> diff
[('-', 'commit e10fab36af376328be5d26371750571757fe3c09 (HEAD -> try-py3.8_venv, origin/try-py3.8_venv)'), ('+', '    re
adme: briefly mention Nose and Robot and providing them extra arguments via the rununittests and runsystemtests sc\r\nri
pts respectively.\r\n\r\ncommit 7eb2584ce47080675bf2a4dffca3bb31946d4f72'), ('=', '\r\nAuthor: Michael Curran <mick@nvac
cess.org>\r\nDate:   '), ('-', 'Mo'), ('+', 'Su'), ('=', 'n Mar '), ('-', '8 00:03:28'), ('+', '7 17:49:43'), ('=', ' 20
21 +1000\r\n\r\n    '), ('-', 'cause a unit test to fail to ensure appveyor aborts.\r\n\r\ncommit b59263d1c21b9e35b8d4e1
7dec58aaeb3507ac6a (origin/py3.8_manualVenv)'), ('+', 'Update system tests readme to talk about runsystemtests, and not
SCons.\r\n\r\ncommit b0cb717278b3561515221620f68d34581a9482d2'), ('=', '\r\nAuthor: Michael Curran <mick@nvaccess.org>\r
\nDate:   Sun Mar 7 1'), ('-', '9:0'), ('+', '7:3'), ('=', '0:5'), ('-', '0'), ('+', '7'), ('=', ' 2021 +1000\r\n\r\n
 '), ('-', 'a'), ('+', 'A'), ('=', 'ppveyor'), ('-', ':'), ('+', ' now'), ('=', ' call'), ('-', ' our batch files as a r
elative path otherise Powershell cannot find them.\r\n\r\ncommit 7b125c6029f60f96febce08a5066d88f55f641cb'), ('+', 's ru
nlint, rununittests and runsystemtests rather than using its own code.\r\n\r\ncommit ed432bf2ac83d0dd0cf1579b179da7e1ece
10207'), ('=', '\r\nAuthor: Michael Curran <mick@nvaccess.org>\r\nDate:   '), ('-', 'Sun'), ('+', 'Thu'), ('=', ' Mar ')
, ('-', '7'), ('+', '4'), ('=', ' 18:3'), ('-', '7:31'), ('+', '3:40'), ('=', ' 2021 +1000\r\n\r\n    '), ('-', 'tests/s
conscript: remove all code unrelated to checkPot.\r\n\r\ncommit ee498f36ccc9e05f5c4cb94f2a688d3e1967cc7a\r\nAuthor: Mich
ael Curran <mick@nvaccess.org>\r\nDate:   Sun Mar 7 17:55:20 2021 +1000'), ('+', 'Remove targets for unit tests, system
tests and linting from SCons as they all now have their own run* commands in t\r\nhe root of the repository which are mu
ch faster to execute.'), ('=', '\r\n\r\n:')]
```

### System configuration
#### NVDA installed/portable/running from source:
Installed and source.

#### NVDA version:
Latest master and Python 3.8 branch.

#### Windows version:
Windows 10 21H1.

#### Name and version of other software in use when reproducing the issue:
cmd (Conhost), inbox build from 21H1.

### Other questions
#### Does the issue still occur after restarting your computer?
N/A.

#### Have you tried any other versions of NVDA? If so, please report their behaviours.
N/A

#### If add-ons are disabled, is your problem still occurring?
N/A

#### Did you try to run the COM registry fixing tool in NVDA menu / tools?
N/A


Discussion:
This also occurs with Difflib and seems to be a result of visible range bounding as the algorithms lose context when the entire screen refreshes.

Resolving patch:
diff --git a/source/NVDAObjects/UIA/winConsoleUIA.py b/source/NVDAObjects/UIA/winConsoleUIA.py
--- a/source/NVDAObjects/UIA/winConsoleUIA.py
+++ b/source/NVDAObjects/UIA/winConsoleUIA.py
@@ -19,6 +19,7 @@
 
 
 class ConsoleUIATextInfo(UIATextInfo):
+	"A TextInfo implementation for consoles with an IMPROVED, but not FORMATTED, API level."
 	def __init__(self, obj, position, _rangeObj=None):
 		collapseToEnd = None
 		# We want to limit  textInfos to just the visible part of the console.
@@ -376,11 +377,12 @@ def _get_TextInfo(self):
 		ConsoleUIATextInfo bounds review to the visible text.
 		ConsoleUIATextInfoWorkaroundEndInclusive fixes expand/collapse and implements
 		word movement."""
-		return (
-			ConsoleUIATextInfo
-			if self.apiLevel >= WinConsoleAPILevel.IMPROVED
-			else ConsoleUIATextInfoWorkaroundEndInclusive
-		)
+		if self.apiLevel >= WinConsoleAPILevel.FORMATTED:
+			return UIATextInfo  # No TextInfo workarounds needed
+		elif self.apiLevel >= WinConsoleAPILevel.IMPROVED:
+			return ConsoleUIATextInfo
+		else:
+			return ConsoleUIATextInfoWorkaroundEndInclusive
 
 	def _get_devInfo(self):
 		info = super().devInfo
@@ -408,5 +410,4 @@ def findExtraOverlayClasses(obj, clsList):
 
 
 class WinTerminalUIA(EnhancedTermTypedCharSupport):
-	def _get_TextInfo(self):
-		return ConsoleUIATextInfo
+	pass


Test patch: