Repository: nvaccess/nvda

Issue:
Global command for reporting destination of a link: Consider reporting for the link at the position of the virtual caret / focus rather than for the navigator object
### Is your feature request related to a problem? Please describe.
In #14583 @XLTechie  added a global commands which allow to report a URL for the link at the position of the navigator object. While this is a **huge** improvement compared to either having copy the URL to the clipboard or accessing the URL from the status bar from the web browser, the fact that these scripts report destination for the link at the navigator object rather than focus / caret position makes their usage impractical for people who prefer to work with review cursor / navigator object not following focus / caret.

### Describe the solution you'd like
Ideally these new scripts should report the URL for the link which is at the position of the virtual caret in  browse mode or for the object with focus. For most users there should be no difference in behavior, since by default navigator object follows focus.
### Describe alternatives you've considered
Leave the behavior as is.
### Additional context
I'm not sure why the navigator object was chosen in the first place, so perhaps there is a good reason which I'm not aware of. Assuming this proposal is accepted we would also have to decide if we need additional scripts for reporting destination of the link at the position of the navigator object - I can't think about any use cases, but perhaps there are some. cc @michaelDCurran and @Qchristensen  for additional input, since both of you reviewed the original implementation.
If this proposal is accepted I would be happy to submit an implementation.


Discussion:
@lukaszgo1
> I'm not sure why the navigator object was chosen in the first place, so perhaps there is a good reason which I'm not aware of.

The fact that the OCR feature uses the navigator object might have influenced me 
to try using that object first, which I did.
But mainly, it was because it seemed like the most reliable way.

The focus object doesn't really work here, especially in virtual buffers, 
because it is rarely where the user is reading. Only if "Automatically set 
system focus to focusable elements" is on. However, since that feature will be 
removed soon, and is off by default, relying on it would be unwise.

The caret object can't be used in this way within virtual buffers, because it 
represents the document.

If you know how to pull what is needed out of the TextInfo at the current caret 
position, then that may be worth exploring; but at the moment I am not fully 
informed about working with textInfos.

If you know what I'm missing to bring this all together, I'll be happy to work 
on it further, but I'm not sure the direction at this point. If you'd rather 
just implement as you mentioned, then go ahead.


Resolving patch:
diff --git a/source/globalCommands.py b/source/globalCommands.py
--- a/source/globalCommands.py
+++ b/source/globalCommands.py
@@ -3630,8 +3630,8 @@ def script_reloadPlugins(self, gesture):
 
 	@script(
 		description=_(
-			# Translators: input help mode message for Report destination URL of navigator link command
-			"Report the destination URL of the link in the navigator object. "
+			# Translators: input help mode message for Report destination URL of a link command
+			"Report the destination URL of the link at the position of caret or focus. "
 			"If pressed twice, shows the URL in a window for easier review."
 		),
 		gesture="kb:NVDA+k",
@@ -3640,25 +3640,39 @@ def script_reloadPlugins(self, gesture):
 	def script_reportLinkDestination(
 			self, gesture: inputCore.InputGesture, forceBrowseable: bool = False
 	) -> None:
-		"""Generates a ui.message or ui.browseableMessage of a link's destination, if the navigator
-		object is a link, or an element with an included link such as a graphic.
+		"""Generates a ui.message or ui.browseableMessage of a link's destination, if focus or caret is
+		positioned on a link, or an element with an included link such as a graphic.
 		@param forceBrowseable: skips the press once check, and displays the browseableMessage version.
 		"""
-		obj = api.getNavigatorObject()
+		try:
+			ti: textInfos.TextInfo = api.getCaretPosition()
+		except RuntimeError:
+			log.debugWarning("Unable to get the caret position.", exc_info=True)
+			ti: textInfos.TextInfo = api.getFocusObject().makeTextInfo(textInfos.POSITION_FIRST)
+		ti.expand(textInfos.UNIT_CHARACTER)
+		obj: NVDAObject = ti.NVDAObjectAtStart
 		presses = scriptHandler.getLastScriptRepeatCount()
 		if (
 			obj.role == controlTypes.role.Role.LINK  # If it's a link, or
 			or controlTypes.state.State.LINKED in obj.states  # if it isn't a link but contains one
 		):
+			linkDestination = obj.value
+			if linkDestination is None:
+				# Translators: Informs the user that the link has no destination
+				ui.message(_("Link has no apparent destination"))
+				return
 			if (
 				presses == 1  # If pressed twice, or
 				or forceBrowseable  # if a browseable message is preferred unconditionally
 			):
-				# Translators: Informs the user that the window contains the destination of the
-				# link with given title
-				ui.browseableMessage(obj.value, title=_("Destination of: {name}").format(name=obj.name))
+				ui.browseableMessage(
+					linkDestination,
+					# Translators: Informs the user that the window contains the destination of the
+					# link with given title
+					title=_("Destination of: {name}").format(name=obj.name)
+				)
 			elif presses == 0:  # One press
-				ui.message(obj.value)  # Speak the link
+				ui.message(linkDestination)  # Speak the link
 			else:  # Some other number of presses
 				return  # Do nothing
 		else:
@@ -3667,8 +3681,8 @@ def script_reportLinkDestination(
 
 	@script(
 		description=_(
-			# Translators: input help mode message for Report URL of navigator link in a window command
-			"Reports the destination URL of the link in the navigator object in a window, "
+			# Translators: input help mode message for Report URL of a link in a window command
+			"Displays the destination URL of the link at the position of caret or focus in a window, "
 			"instead of just speaking it. May be preferred by braille users."
 		),
 		category=SCRCAT_TOOLS


Test patch: