content,internal: add support for stdlib pageType label

The Standard library page is no longer labeled as module, and all stdlib
packages are labeled with the "stdlib" label.

pageInfo is refactored and split into pageTitle, pageType, and
pageLabels.

Change-Id: I59cec2e05de01b6c0b191e428e8229fc95d67b2e
Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/259999
Trust: Julie Qiu <julie@golang.org>
Run-TryBot: Julie Qiu <julie@golang.org>
TryBot-Result: kokoro <noreply+kokoro@google.com>
Reviewed-by: Jamal Carvalho <jamal@golang.org>
diff --git a/content/static/html/helpers/_unit_fixed_header.tmpl b/content/static/html/helpers/_unit_fixed_header.tmpl
index 4fa7adf..7b5cac9 100644
--- a/content/static/html/helpers/_unit_fixed_header.tmpl
+++ b/content/static/html/helpers/_unit_fixed_header.tmpl
@@ -12,11 +12,11 @@
       </a>
       <div class="UnitFixedHeader-moduleInfo">
         <span class="UnitFixedHeader-title">
-          {{if ne .PageType "std"}}
-            <span class="UnitFixedHeader-titleName">{{.Title}}</span>
-          {{else}}
+          {{if eq .PageType "std"}}
             <span class="UnitFixedHeader-titleType">Standard library</span>
             <span class="UnitFixedHeader-titleType UnitFixedHeader-titleType--small">StdLib</span>
+          {{else}}
+            <span class="UnitFixedHeader-titleName">{{.Title}}</span>
           {{end}}
         </span>
         {{with .Breadcrumb}}
@@ -100,4 +100,4 @@
       </div>
     </div>
   </div>
-{{end}}
\ No newline at end of file
+{{end}}
diff --git a/content/static/html/helpers/_unit_header.tmpl b/content/static/html/helpers/_unit_header.tmpl
index 95da358..90f9a45 100644
--- a/content/static/html/helpers/_unit_header.tmpl
+++ b/content/static/html/helpers/_unit_header.tmpl
@@ -36,16 +36,17 @@
         <h1 class="UnitHeader-title">
           {{.Title}}
         </h1>
-        {{if .Unit.IsCommand}}
-          <span class="UnitHeader-badge">command</span>
-        {{else if .Unit.IsPackage}}
-          <span class="UnitHeader-badge">package</span>
-        {{end}}
-        {{if .Unit.IsModule}}
-          <span class="UnitHeader-badge">module</span>
-        {{end}}
-        {{if not (or .Unit.IsPackage .Unit.IsModule)}}
-          <span class="UnitHeader-badge">directory</span>
+        {{range .PageLabels}}
+          {{if ne . "std"}}
+            <span class="UnitHeader-badge">
+              {{if eq . "pkg"}}package
+              {{else if eq . "cmd"}}command
+              {{else if eq . "mod"}}module
+              {{else if eq . "dir"}}directory
+              {{else if eq . "stdlib"}}standard library
+              {{end}}
+            </span>
+          {{end}}
         {{end}}
       </div>
       <div class="UnitHeader-versionBanner $$GODISCOVERY_LATESTMAJORCLASS$$">
diff --git a/internal/frontend/details.go b/internal/frontend/details.go
index ea1c19f..4101876 100644
--- a/internal/frontend/details.go
+++ b/internal/frontend/details.go
@@ -68,7 +68,8 @@
 	pageTypeDirectory = "dir"
 	pageTypePackage   = "pkg"
 	pageTypeCommand   = "cmd"
-	pageTypeStdLib    = stdlib.ModulePath
+	pageTypeStdlib    = "stdlib"
+	pageTypeModuleStd = "std"
 )
 
 var (
diff --git a/internal/frontend/latest_version.go b/internal/frontend/latest_version.go
index c4e6b7f..24aa684 100644
--- a/internal/frontend/latest_version.go
+++ b/internal/frontend/latest_version.go
@@ -51,7 +51,7 @@
 func latestMinorVersion(ctx context.Context, ds internal.DataSource, packagePath, modulePath, pageType string) (_ string, err error) {
 	defer derrors.Wrap(&err, "latestMinorVersion(ctx, %q, %q)", modulePath, packagePath)
 	fullPath := packagePath
-	if pageType == pageTypeModule || pageType == pageTypeStdLib {
+	if pageType == pageTypeModule || pageType == pageTypeModuleStd {
 		fullPath = modulePath
 	}
 	um, err := ds.GetUnitMeta(ctx, fullPath, modulePath, internal.LatestVersion)
diff --git a/internal/frontend/module.go b/internal/frontend/module.go
index 6e07189..c0261ae 100644
--- a/internal/frontend/module.go
+++ b/internal/frontend/module.go
@@ -41,7 +41,7 @@
 	}
 	pageType := pageTypeModule
 	if um.ModulePath == stdlib.ModulePath {
-		pageType = pageTypeStdLib
+		pageType = pageTypeModuleStd
 	}
 
 	page := &DetailsPage{
diff --git a/internal/frontend/unit.go b/internal/frontend/unit.go
index 8e442dd..e22e798 100644
--- a/internal/frontend/unit.go
+++ b/internal/frontend/unit.go
@@ -67,9 +67,13 @@
 	// LatestURL is a url pointing to the latest version of a unit.
 	LatestURL string
 
-	// PageType is the type of page (pkg, cmd, dir, etc.).
+	// PageType is the type of page (pkg, cmd, dir, std, or mod).
 	PageType string
 
+	// PageLabels are the labels that will be displayed
+	// for a given page.
+	PageLabels []string
+
 	// CanShowDetails indicates whether details can be shown or must be
 	// hidden due to issues like license restrictions.
 	CanShowDetails bool
@@ -251,7 +255,7 @@
 		return nil
 	}
 
-	title, pageType := pageInfo(unit)
+	title := pageTitle(unit)
 	basePage := s.newBasePage(r, title)
 	basePage.AllowWideContent = true
 	canShowDetails := unit.IsRedistributable || tabSettings.AlwaysShowDetails
@@ -280,7 +284,8 @@
 		DisplayVersion:  displayVersion(unit.Version, unit.ModulePath),
 		LinkVersion:     linkVersion(unit.Version, unit.ModulePath),
 		LatestURL:       constructPackageURL(unit.Path, unit.ModulePath, middleware.LatestMinorVersionPlaceholder),
-		PageType:        pageType,
+		PageLabels:      pageLabels(unit),
+		PageType:        pageType(unit),
 		CanShowDetails:  canShowDetails,
 		UnitContentName: tabSettings.DisplayName,
 		Readme:          readme,
@@ -343,21 +348,62 @@
 	return safehtml.HTML{}, nil
 }
 
-// pageInfo determines the title and pageType for a given unit.
-func pageInfo(unit *internal.Unit) (title string, pageType string) {
+// pageTitle determines the pageTitles for a given unit.
+// See TestPageTitlesAndTypes for examples.
+func pageTitle(unit *internal.Unit) string {
+	switch {
+	case unit.Path == stdlib.ModulePath:
+		return "Standard library"
+	case unit.IsCommand():
+		return effectiveName(unit.Path, unit.Name)
+	case unit.IsPackage():
+		return unit.Name
+	case unit.IsModule():
+		return path.Base(unit.Path)
+	default:
+		return path.Base(unit.Path) + "/"
+	}
+}
+
+// pageType determines the pageType for a given unit.
+func pageType(unit *internal.Unit) string {
 	if unit.Path == stdlib.ModulePath {
-		return "Standard library", pageTypeStdLib
+		return pageTypeModuleStd
 	}
 	if unit.IsCommand() {
-		return effectiveName(unit.Path, unit.Name), pageTypeCommand
+		return pageTypeCommand
 	}
 	if unit.IsPackage() {
-		return unit.Name, pageTypePackage
+		return pageTypePackage
 	}
 	if unit.IsModule() {
-		return path.Base(unit.Path), pageTypeModule
+		return pageTypeModule
 	}
-	return path.Base(unit.Path) + "/", pageTypeDirectory
+	return pageTypeDirectory
+}
+
+// pageLabels determines the labels to display for a given unit.
+// See TestPageTitlesAndTypes for examples.
+func pageLabels(unit *internal.Unit) []string {
+	var pageTypes []string
+	if unit.Path == stdlib.ModulePath {
+		return nil
+	}
+	if unit.IsCommand() {
+		pageTypes = append(pageTypes, pageTypeCommand)
+	} else if unit.IsPackage() {
+		pageTypes = append(pageTypes, pageTypePackage)
+	}
+	if unit.IsModule() {
+		pageTypes = append(pageTypes, pageTypeModule)
+	}
+	if !unit.IsPackage() && !unit.IsModule() {
+		pageTypes = append(pageTypes, pageTypeDirectory)
+	}
+	if stdlib.Contains(unit.Path) {
+		pageTypes = append(pageTypes, pageTypeStdlib)
+	}
+	return pageTypes
 }
 
 // displayBreadcrumbs appends additional breadcrumb links for display
diff --git a/internal/frontend/unit_test.go b/internal/frontend/unit_test.go
index 68c616b..5ace0f6 100644
--- a/internal/frontend/unit_test.go
+++ b/internal/frontend/unit_test.go
@@ -15,41 +15,68 @@
 	"golang.org/x/pkgsite/internal/testing/sample"
 )
 
-func TestPageInfo(t *testing.T) {
-	m := sample.LegacyModule("golang.org/x/tools", "v1.0.0", "go/packages", "cmd/godoc")
+type testUnitPage struct {
+	unit       *internal.Unit
+	name       string
+	wantTitle  string
+	wantType   string
+	wantLabels []string
+}
 
-	type test struct {
-		name      string
-		unit      *internal.Unit
-		wantTitle string
-		wantType  string
-	}
-	var tests []*test
+func TestPageTitlePageTypePageLabels(t *testing.T) {
+
+	var tests []*testUnitPage
+	m := sample.LegacyModule("golang.org/x/tools", "v1.0.0", "go/packages", "cmd/godoc")
 	for _, u := range m.Units {
 		switch u.Path {
 		case "golang.org/x/tools":
-			tests = append(tests, &test{"module golang.org/x/tools", u, "tools", pageTypeModule})
+			tests = append(tests, &testUnitPage{u, "module golang.org/x/tools", "tools", pageTypeModule, []string{pageTypeModule}})
 		case "golang.org/x/tools/go/packages":
-			tests = append(tests, &test{"package golang.org/x/tools/go/packages", u, "packages", pageTypePackage})
+			tests = append(tests, &testUnitPage{u, "package golang.org/x/tools/go/packages", "packages", pageTypePackage, []string{pageTypePackage}})
 		case "golang.org/x/tools/go":
-			tests = append(tests, &test{"directory golang.org/x/tools/go", u, "go/", pageTypeDirectory})
+			tests = append(tests, &testUnitPage{u, "directory golang.org/x/tools/go", "go/", pageTypeDirectory, []string{pageTypeDirectory}})
 		case "golang.org/x/tools/cmd/godoc":
 			u.Name = "main"
-			tests = append(tests, &test{"package golang.org/x/tools/cmd/godoc", u, "godoc", pageTypeCommand})
+			tests = append(tests, &testUnitPage{u, "package golang.org/x/tools/cmd/godoc", "godoc", pageTypeCommand, []string{pageTypeCommand}})
 		case "golang.org/x/tools/cmd":
-			tests = append(tests, &test{"directory golang.org/x/tools/cmd", u, "cmd/", pageTypeDirectory})
+			tests = append(tests, &testUnitPage{u, "directory golang.org/x/tools/cmd", "cmd/", pageTypeDirectory, []string{pageTypeDirectory}})
 		default:
 			t.Fatalf("Unexpected path: %q", u.Path)
 		}
 	}
-	std := sample.LegacyModule(stdlib.ModulePath, "v1.0.0", "")
-	tests = append(tests, &test{"module std", std.Units[0], "Standard library", pageTypeStdLib})
+
+	m2 := sample.LegacyModule("golang.org/x/tools/gopls", "v1.0.0", "")
+	m2.Units[0].Name = "main"
+	tests = append(tests, &testUnitPage{m2.Units[0], "module golang.org/x/tools/gopls", "gopls", pageTypeCommand, []string{pageTypeCommand, pageTypeModule}})
+
+	std := sample.LegacyModule(stdlib.ModulePath, "v1.0.0", "cmd/go")
+	for _, u := range std.Units {
+		switch u.Path {
+		case stdlib.ModulePath:
+			tests = append(tests, &testUnitPage{u, "module std", "Standard library", pageTypeModuleStd, nil})
+		case "cmd":
+			tests = append(tests, &testUnitPage{u, "directory cmd", "cmd/", pageTypeDirectory, []string{pageTypeDirectory, pageTypeStdlib}})
+		case "cmd/go":
+			u.Name = "main"
+			tests = append(tests, &testUnitPage{u, "command go", "go", pageTypeCommand, []string{pageTypeCommand, pageTypeStdlib}})
+		default:
+			t.Fatalf("Unexpected path: %q", u.Path)
+		}
+	}
 
 	for _, test := range tests {
 		t.Run(test.name, func(t *testing.T) {
-			gotTitle, gotType := pageInfo(test.unit)
-			if gotTitle != test.wantTitle || gotType != test.wantType {
-				t.Errorf("pageInfo(%q): %q, %q; want = %q, %q", test.unit.Path, gotTitle, gotType, test.wantTitle, test.wantType)
+			gotTitle := pageTitle(test.unit)
+			if gotTitle != test.wantTitle {
+				t.Errorf("pageTitle(%q): %q; want = %q", test.unit.Path, gotTitle, test.wantTitle)
+			}
+			gotType := pageType(test.unit)
+			if gotType != test.wantType {
+				t.Errorf("pageType(%q): %q; want = %q", test.unit.Path, gotType, test.wantType)
+			}
+			gotLabels := pageLabels(test.unit)
+			if diff := cmp.Diff(test.wantLabels, gotLabels); diff != "" {
+				t.Errorf("mismatch on pageLabels (-want +got):\n%s", diff)
 			}
 		})
 	}