gopls/internal/hooks, internal/lsp/source: only match full words in link regexes

The current URL regexes (including xurls) match links in any part of a
string. However, this leads to odd underlining within words which just
so happen to have valid domain names as substrings. For example, a
comment which contains "reflect.DeepEqual" will match the URL regex as
"reflect.de" is a domain name.

Ensure that the URLs only match full regex words by adding \b around the
expressions. For xurls, this is done by pulling the expression out of
Relaxed() and recreating the Regexp.

While I'm here, make the non-gopls module expression prefer the longest
match, as xurls does.

Change-Id: I403db970fa1661c443b0693c03f8dee114f8eaff
Reviewed-on: https://go-review.googlesource.com/c/tools/+/240738
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
diff --git a/gopls/internal/hooks/hooks.go b/gopls/internal/hooks/hooks.go
index 6238da6..218689e 100644
--- a/gopls/internal/hooks/hooks.go
+++ b/gopls/internal/hooks/hooks.go
@@ -8,6 +8,8 @@
 package hooks // import "golang.org/x/tools/gopls/internal/hooks"
 
 import (
+	"regexp"
+
 	"golang.org/x/tools/internal/lsp/source"
 	"mvdan.cc/xurls/v2"
 )
@@ -16,6 +18,13 @@
 	if options.GoDiff {
 		options.ComputeEdits = ComputeEdits
 	}
-	options.URLRegexp = xurls.Relaxed()
+	options.URLRegexp = urlRegexp()
 	updateAnalyzers(options)
 }
+
+func urlRegexp() *regexp.Regexp {
+	// Ensure links are matched as full words, not anywhere.
+	re := regexp.MustCompile(`\b(` + xurls.Relaxed().String() + `)\b`)
+	re.Longest()
+	return re
+}
diff --git a/internal/lsp/source/options.go b/internal/lsp/source/options.go
index 6e785e1..cde7a7a 100644
--- a/internal/lsp/source/options.go
+++ b/internal/lsp/source/options.go
@@ -132,7 +132,7 @@
 		},
 		Hooks: Hooks{
 			ComputeEdits:         myers.ComputeEdits,
-			URLRegexp:            regexp.MustCompile(`(http|ftp|https)://([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?`),
+			URLRegexp:            urlRegexp(),
 			DefaultAnalyzers:     defaultAnalyzers(),
 			TypeErrorAnalyzers:   typeErrorAnalyzers(),
 			ConvenienceAnalyzers: convenienceAnalyzers(),
@@ -702,3 +702,10 @@
 		simplifyslice.Analyzer.Name:        {Analyzer: simplifyslice.Analyzer, enabled: true, HighConfidence: true},
 	}
 }
+
+func urlRegexp() *regexp.Regexp {
+	// Ensure links are matched as full words, not anywhere.
+	re := regexp.MustCompile(`\b(http|ftp|https)://([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?\b`)
+	re.Longest()
+	return re
+}