internal/frontend: default capitalized query to symbol search
If a query contains one word, and that word is capitalized, assume the
user is searching for a symbol and not a package.
For golang/go#44142
Change-Id: I220245ab5c941fcf1651a733a9fdc5aa423a6307
Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/346114
Trust: Julie Qiu <julie@golang.org>
Run-TryBot: Julie Qiu <julie@golang.org>
TryBot-Result: kokoro <noreply+kokoro@google.com>
Reviewed-by: Jonathan Amsterdam <jba@google.com>
diff --git a/internal/frontend/search.go b/internal/frontend/search.go
index f6902d0..d70ec24 100644
--- a/internal/frontend/search.go
+++ b/internal/frontend/search.go
@@ -14,9 +14,11 @@
"sort"
"strings"
"time"
+ "unicode"
"unicode/utf8"
"github.com/google/safehtml/template"
+ "golang.org/x/mod/semver"
"golang.org/x/pkgsite/internal"
"golang.org/x/pkgsite/internal/derrors"
"golang.org/x/pkgsite/internal/experiment"
@@ -407,18 +409,34 @@
return q, mode == searchModeSymbol
}
-// shouldDefaultToSymbolSearch reports whether the search query is of the form
-// <package>.<symbol>. The <symbol> component should not be a top-level domain
-// that is in our database.
+// shouldDefaultToSymbolSearch reports whether the symbol search mode should
+// default to symbol search mode based on the input.
func shouldDefaultToSymbolSearch(q string) bool {
- if len(strings.Fields(q)) != 1 || !strings.ContainsAny(q, ".") {
+ if len(strings.Fields(q)) != 1 {
return false
}
if internal.IsGoPkgInPathElement(q) {
return false
}
parts := strings.Split(q, ".")
- return !internal.TopLevelDomains[parts[len(parts)-1]]
+ if len(parts) > 1 {
+ if len(parts) == 2 && semver.IsValid(parts[1]) {
+ // The q has the format <text>.<semver> which is likely a
+ // gopkg.in host, such as yaml.v2. Default to package search.
+ return false
+ }
+ return !internal.TopLevelDomains[parts[len(parts)-1]]
+ }
+ // If a user searches for "Unmarshal", assume that they are searching for
+ // the symbol name "Unmarshal", not the package unmarshal.
+ return isCapitalized(q)
+}
+
+func isCapitalized(s string) bool {
+ if len(s) == 0 {
+ return false
+ }
+ return unicode.IsUpper(rune(s[0]))
}
// elapsedTime takes a date and returns returns human-readable,
diff --git a/internal/frontend/search_test.go b/internal/frontend/search_test.go
index 3e86bf2..415119b 100644
--- a/internal/frontend/search_test.go
+++ b/internal/frontend/search_test.go
@@ -411,6 +411,7 @@
{"sql.DB.Begin", true},
{"yaml.v2", false},
{"gopkg.in", false},
+ {"Unmarshal", true},
} {
t.Run(test.q, func(t *testing.T) {
got := shouldDefaultToSymbolSearch(test.q)
diff --git a/tests/search/scripts/default.txt b/tests/search/scripts/default.txt
index 92f7132..87b0af7 100644
--- a/tests/search/scripts/default.txt
+++ b/tests/search/scripts/default.txt
@@ -43,3 +43,11 @@
keyboard shorcut "package:"
[] package:Foo
gopkg.in/foo.v1
+
+capital letter one word defaults to symbol mode
+[symbol] Float
+Float math/big
+
+non-TLD word.word defaults to symbol mode
+[symbol] big.Float
+Float math/big