Repository: nvaccess/nvda

Issue:
Add ability to retrieve formatting for the text under the cared
### Is your feature request related to a problem? Please describe.
I am working all the time with review cursor and object navigation not following the cared mainly to be able to for instance read some instructions with the review cursor in the one window and work at the same time in the other program like sighted people are working by placing two windows side by side. Therefore each actions which require me to move review cursor from its current position  slows me down considerably. One thing which I need to check relatively often is formatting of the text either when working in MS Word, or when composing some CSS. Currently to do this I have to either move my review cursor to my working window and lost my place of reading, or have braille display connected and use command to check formatting for the specific braille cell.
I propose adding script to check formatting under the cared not only for workflows like mine, but also not to make non braille users disadvantaged.
### Describe the solution you'd like
As by default position of the review cursor and the cared is the same for most users pressing NVDA+F would report formatting of the character under the cared. In my opinion it makes sense to make NVDA+F report formatting under the cared and assign script for reporting formatting under the review cursor to the NVDA+Shift+F.
### Describe alternatives you've considered
We can leave current assignment as is and create new script for reporting formatting under the cared unassigned.
### Additional context
In most screen readers retrieving formatting under the cared is possible, and ad least for me it would be very beneficial.
I can work on this it don't seems to be hard in terms of coding, however it would be nice to have confirmation from @michaelDCurran or @feerrenrut that the feature would be approved and which of the two above solutions would you prefer.


Discussion:
I recall there either is an issue for this already, or this has been discussed on a mailing list. Anyhow, this is a valid request and is not very difficult to implement, as long as the implementation ensures that the script only works when there is a caret.
See issue #7869 and #8674 and PR #7990. A checkbox in the Document Formatting Settings would be fine as (later on) it should be possible to configure which formatting values should be spoken (and shown via Braille flash message) via NVDA+F and shown after Double-NVDA+F in a separate window.

Resolving patch:
diff --git a/source/globalCommands.py b/source/globalCommands.py
--- a/source/globalCommands.py
+++ b/source/globalCommands.py
@@ -1,9 +1,9 @@
 # -*- coding: UTF-8 -*-
-#globalCommands.py
-#A part of NonVisual Desktop Access (NVDA)
-#This file is covered by the GNU General Public License.
-#See the file COPYING for more details.
-#Copyright (C) 2006-2018 NV Access Limited, Peter Vágner, Aleksey Sadovoy, Rui Batista, Joseph Lee, Leonard de Ruijter, Derek Riemer, Babbage B.V., Davy Kager, Ethan Holliger, Łukasz Golonka
+# A part of NonVisual Desktop Access (NVDA)
+# This file is covered by the GNU General Public License.
+# See the file COPYING for more details.
+# Copyright (C) 2006-2020 NV Access Limited, Peter Vágner, Aleksey Sadovoy, Rui Batista, Joseph Lee,
+# Leonard de Ruijter, Derek Riemer, Babbage B.V., Davy Kager, Ethan Holliger, Łukasz Golonka
 
 import time
 import itertools
@@ -1391,6 +1391,8 @@ def script_sayAll(self,gesture):
 	def _reportFormattingHelper(self, info, browseable=False):
 		# Report all formatting-related changes regardless of user settings
 		# when explicitly requested.
+		if info is None:
+			return
 		# These are the options we want reported when reporting formatting manually.
 		# for full list of options that may be reported see the "documentFormatting" section of L{config.configSpec}
 		reportFormattingOptions = (
@@ -1463,16 +1465,87 @@ def _reportFormattingHelper(self, info, browseable=False):
 				_("Formatting")
 			)
 
-	def script_reportFormatting(self,gesture):
-		info=api.getReviewPosition()
-		repeats=scriptHandler.getLastScriptRepeatCount()
-		if repeats==0:
-			self._reportFormattingHelper(info,False)
-		elif repeats==1:
-			self._reportFormattingHelper(info,True)
-	# Translators: Input help mode message for report formatting command.
-	script_reportFormatting.__doc__ = _("Reports formatting info for the current review cursor position within a document. If pressed twice, presents the information in browse mode")
-	script_reportFormatting.category=SCRCAT_TEXTREVIEW
+	def _getTIAtCaret(self):
+		# Returns text info at the caret position if there is a caret in the current control, None otherwise.
+		# Note that if there is  no caret this fact is announced  in speech and braille.
+		obj = api.getFocusObject()
+		treeInterceptor = obj.treeInterceptor
+		if(
+			isinstance(treeInterceptor, treeInterceptorHandler.DocumentTreeInterceptor)
+			and not treeInterceptor.passThrough
+		):
+			obj = treeInterceptor
+		try:
+			info = obj.makeTextInfo(textInfos.POSITION_CARET)
+			return info
+		except (NotImplementedError, RuntimeError):
+			# Translators: Reported when there is no caret.
+			ui.message(_("No caret"))
+			return
+
+	@script(
+		# Translators: Input help mode message for report formatting command.
+		description=_("Reports formatting info for the current review cursor position."),
+		category=SCRCAT_TEXTREVIEW,
+	)
+	def script_reportFormattingAtReview(self, gesture):
+		self._reportFormattingHelper(api.getReviewPosition(), False)
+
+	@script(
+		# Translators: Input help mode message for show formatting at review cursor command.
+		description=_("Presents, in browse mode, formatting info for the current review cursor position."),
+		category=SCRCAT_TEXTREVIEW,
+	)
+	def script_showFormattingAtReview(self, gesture):
+		self._reportFormattingHelper(api.getReviewPosition(), True)
+
+	@script(
+		description=_(
+			# Translators: Input help mode message for report formatting command.
+			"Reports formatting info for the current review cursor position."
+			" If pressed twice, presents the information in browse mode"
+		),
+		category=SCRCAT_TEXTREVIEW,
+		gesture="kb:NVDA+shift+f",
+	)
+	def script_reportFormatting(self, gesture):
+		repeats = scriptHandler.getLastScriptRepeatCount()
+		if repeats == 0:
+			self.script_reportFormattingAtReview(gesture)
+		elif repeats == 1:
+			self.script_showFormattingAtReview(gesture)
+
+	@script(
+		# Translators: Input help mode message for report formatting at caret command.
+		description=_("Reports formatting info for the text under the caret."),
+		category=SCRCAT_SYSTEMCARET,
+	)
+	def script_reportFormattingAtCaret(self, gesture):
+		self._reportFormattingHelper(self._getTIAtCaret(), False)
+
+	@script(
+		# Translators: Input help mode message for show formatting at caret position command.
+		description=_("Presents, in browse mode, formatting info for the text under the caret."),
+		category=SCRCAT_SYSTEMCARET,
+	)
+	def script_showFormattingAtCaret(self, gesture):
+		self._reportFormattingHelper(self._getTIAtCaret(), True)
+
+	@script(
+		description=_(
+			# Translators: Input help mode message for report formatting at caret command.
+			"Reports formatting info for the text under the caret."
+			" If pressed twice, presents the information in browse mode"
+		),
+		category=SCRCAT_SYSTEMCARET,
+		gesture="kb:NVDA+f",
+	)
+	def script_reportOrShowFormattingAtCaret(self, gesture):
+		repeats = scriptHandler.getLastScriptRepeatCount()
+		if repeats == 0:
+			self.script_reportFormattingAtCaret(gesture)
+		elif repeats == 1:
+			self.script_showFormattingAtCaret(gesture)
 
 	def script_reportCurrentFocus(self,gesture):
 		focusObject=api.getFocusObject()
@@ -2625,8 +2698,6 @@ def _enableScreenCurtain(doEnable: bool = True):
 		"kb(laptop):NVDA+l": "reportCurrentLine",
 		"kb(desktop):NVDA+shift+upArrow": "reportCurrentSelection",
 		"kb(laptop):NVDA+shift+s": "reportCurrentSelection",
-		"kb:NVDA+f": "reportFormatting",
-
 		# Object navigation
 		"kb:NVDA+numpad5": "navigatorObject_current",
 		"kb(laptop):NVDA+shift+o": "navigatorObject_current",


Test patch: