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
67import objbase
78import comtypes
1415from comtypes .automation import IDispatch
1516from NVDAObjects .window import DisplayModelEditableText
1617from NVDAObjects .IAccessible import IAccessible
17- from NVDAObjects .UIA import UIA
18+ from NVDAObjects .UIA import UIA , WpfTextView , UIATextInfo
1819from enum import IntEnum
1920import appModuleHandler
2021import controlTypes
2122import 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+
85137class VsTextEditPaneTextInfo (textInfos .offsets .OffsetsTextInfo ):
86138
87139 def _get__selectionObject (self ):
0 commit comments