Skip to content

Commit ce35702

Browse files
authored
Merge 43982a7 into 21367c8
2 parents 21367c8 + 43982a7 commit ce35702

1 file changed

Lines changed: 55 additions & 3 deletions

File tree

source/appModules/devenv.py

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
# A part of NonVisual Desktop Access (NVDA)
22
# This file is covered by the GNU General Public License.
33
# See the file COPYING for more details.
4-
# Copyright (C) 2010-2019 NV Access Limited, Soronel Haetir, Babbage B.V., Francisco Del Roio
4+
# Copyright (C) 2010-2022 NV Access Limited, Soronel Haetir, Babbage B.V., Francisco Del Roio,
5+
# Leonard de Ruijter
56

67
import objbase
78
import comtypes
@@ -14,11 +15,12 @@
1415
from comtypes.automation import IDispatch
1516
from NVDAObjects.window import DisplayModelEditableText
1617
from NVDAObjects.IAccessible import IAccessible
17-
from NVDAObjects.UIA import UIA
18+
from NVDAObjects.UIA import UIA, WpfTextView, UIATextInfo
1819
from enum import IntEnum
1920
import appModuleHandler
2021
import controlTypes
2122
import threading
23+
import UIAHandler
2224

2325

2426
# A few helpful constants
@@ -43,9 +45,12 @@ def __init__(self, *args, **kwargs):
4345
self.vsMajor, self.vsMinor = int(vsMajor), int(vsMinor)
4446

4547
def chooseNVDAObjectOverlayClasses(self, obj, clsList):
48+
if WpfTextView in clsList:
49+
clsList.remove(WpfTextView)
50+
clsList.insert(0, VsWpfTextView)
4651
# Only use this overlay class if the top level automation object for the IDE can be retrieved,
4752
# as it will not work otherwise.
48-
if obj.windowClassName == "VsTextEditPane" and self.DTE:
53+
elif obj.windowClassName == "VsTextEditPane" and self.DTE:
4954
try:
5055
clsList.remove(DisplayModelEditableText)
5156
except ValueError:
@@ -82,6 +87,53 @@ def _get_DTE(self):
8287
return DTE
8388

8489

90+
class VsWpfTextViewTextInfo(UIATextInfo):
91+
92+
def _getFormatFieldAtRange(self, textRange, formatConfig, ignoreMixedValues=False):
93+
formatField = super()._getFormatFieldAtRange(textRange, formatConfig, ignoreMixedValues=ignoreMixedValues)
94+
if not formatField:
95+
return formatField
96+
# Visual Studio exposes line numbers as part of the actual text.
97+
# We want to store the line number in a format field instead.
98+
# Therefore, always try to isolate the line number, even when we don't care about reporting it.
99+
lineNumberRange = textRange.Clone()
100+
lineNumberRange.MoveEndpointByRange(
101+
UIAHandler.TextPatternRangeEndpoint_End,
102+
lineNumberRange,
103+
UIAHandler.TextPatternRangeEndpoint_Start
104+
)
105+
lineNumberStr = lineNumberRange.GetText(-1)
106+
if lineNumberStr:
107+
try:
108+
formatField.field['line-number'] = int(lineNumberStr)
109+
except ValueError:
110+
pass
111+
return formatField
112+
113+
def getTextWithFields(self, formatConfig=None):
114+
fields = super().getTextWithFields(formatConfig=formatConfig)
115+
if len(fields) == 0:
116+
# Nothing to do... was probably a collapsed range.
117+
return fields
118+
# Visual Studio exposes line numbers as part of the actual text.
119+
lineNumber = None
120+
for index in range(len(fields)):
121+
field = fields[index]
122+
if isinstance(field, textInfos.FieldCommand) and field.command == "formatChange":
123+
lineNumber = field.field.get("line-number")
124+
elif lineNumber is not None and isinstance(field, str):
125+
# This is the first text string within the list.
126+
# Strip the line number from the string.
127+
lineNumberStr = f"{lineNumber} "
128+
fields[index] = field[len(lineNumberStr):]
129+
break
130+
return fields
131+
132+
133+
class VsWpfTextView(WpfTextView):
134+
TextInfo = VsWpfTextViewTextInfo
135+
136+
85137
class VsTextEditPaneTextInfo(textInfos.offsets.OffsetsTextInfo):
86138

87139
def _get__selectionObject(self):

0 commit comments

Comments
 (0)