mirror of
https://github.com/gohugoio/hugo.git
synced 2026-08-30 10:12:40 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2a663b1938 |
@@ -4,7 +4,7 @@ parameters:
|
||||
defaults: &defaults
|
||||
resource_class: large
|
||||
docker:
|
||||
- image: bepsays/ci-hugoreleaser:1.22400.20000
|
||||
- image: bepsays/ci-hugoreleaser:1.22301.20401
|
||||
environment: &buildenv
|
||||
GOMODCACHE: /root/project/gomodcache
|
||||
version: 2
|
||||
@@ -58,7 +58,7 @@ jobs:
|
||||
environment:
|
||||
<<: [*buildenv]
|
||||
docker:
|
||||
- image: bepsays/ci-hugoreleaser-linux-arm64:1.22400.20000
|
||||
- image: bepsays/ci-hugoreleaser-linux-arm64:1.22301.20401
|
||||
steps:
|
||||
- *restore-cache
|
||||
- &attach-workspace
|
||||
|
||||
@@ -46,4 +46,3 @@ jobs:
|
||||
platforms: linux/amd64,linux/arm64
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
build-args: HUGO_BUILD_TAGS=extended,withdeploy
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
test:
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [1.23.x, 1.24.x]
|
||||
go-version: [1.22.x, 1.23.x]
|
||||
os: [ubuntu-latest, windows-latest] # macos disabled for now because of disk space issues.
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
|
||||
+1
-2
@@ -1,4 +1,4 @@
|
||||
>**Note:** We would appreciate if you hold on with any big refactoring (like renaming deprecated Go packages), mainly because of potential for extra merge work for future coming in in the near future.
|
||||
>**Note:** We would apprecitate if you hold on with any big refactorings (like renaming deprecated Go packages), mainly because of potential for extra merge work for future coming in in the near future.
|
||||
|
||||
# Contributing to Hugo
|
||||
|
||||
@@ -93,7 +93,6 @@ Most title/subjects should have a lower-cased prefix with a colon and one whites
|
||||
* If this commit touches many packages without a common functional topic, prefix with `all:` (e.g. `all: Reformat Go code`)
|
||||
* If this is a documentation update, prefix with `docs:`.
|
||||
* If nothing of the above applies, just leave the prefix out.
|
||||
* Note that the above excludes nouns seen in other repositories, e.g. "chore:".
|
||||
|
||||
Also, if your commit references one or more GitHub issues, always end your commit message body with *See #1234* or *Fixes #1234*.
|
||||
Replace *1234* with the GitHub issue ID. The last example will close the issue when the commit is merged into *master*.
|
||||
|
||||
@@ -34,7 +34,6 @@ A fast and flexible static site generator built with love by [bep], [spf13], and
|
||||
[](https://goreportcard.com/report/github.com/gohugoio/hugo)
|
||||
|
||||
[Website] | [Installation] | [Documentation] | [Support] | [Contributing] | <a rel="me" href="https://fosstodon.org/@gohugoio">Mastodon</a>
|
||||
|
||||
## Overview
|
||||
|
||||
Hugo is a [static site generator] written in [Go], optimized for speed and designed for flexibility. With its advanced templating system and fast asset pipelines, Hugo renders a complete site in seconds, often less.
|
||||
@@ -70,23 +69,6 @@ See the [features] section of the documentation for a comprehensive summary of H
|
||||
<a href="https://www.jetbrains.com/go/?utm_source=OSS&utm_medium=referral&utm_campaign=hugo" target="_blank"><img src="https://raw.githubusercontent.com/gohugoio/gohugoioTheme/master/assets/images/sponsors/goland.svg" width="200" alt="The complete IDE crafted for professional Go developers."></a>
|
||||
</p>
|
||||
|
||||
## Editions
|
||||
|
||||
Hugo is available in three editions: standard, extended, and extended/deploy. While the standard edition provides core functionality, the extended and extended/deploy editions offer advanced features.
|
||||
|
||||
Feature|extended edition|extended/deploy edition
|
||||
:--|:-:|:-:
|
||||
Encode to the WebP format when [processing images]. You can decode WebP images with any edition.|:heavy_check_mark:|:heavy_check_mark:
|
||||
[Transpile Sass to CSS] using the embedded LibSass transpiler. You can use the [Dart Sass] transpiler with any edition.|:heavy_check_mark:|:heavy_check_mark:
|
||||
Deploy your site directly to a Google Cloud Storage bucket, an AWS S3 bucket, or an Azure Storage container. See [details].|:x:|:heavy_check_mark:
|
||||
|
||||
[dart sass]: https://gohugo.io/functions/css/sass/#dart-sass
|
||||
[processing images]: https://gohugo.io/content-management/image-processing/
|
||||
[transpile sass to css]: https://gohugo.io/functions/css/sass/
|
||||
[details]: https://gohugo.io/hosting-and-deployment/hugo-deploy/
|
||||
|
||||
Unless your specific deployment needs require the extended/deploy edition, we recommend the extended edition.
|
||||
|
||||
## Installation
|
||||
|
||||
Install Hugo from a [prebuilt binary], package manager, or package repository. Please see the installation instructions for your operating system:
|
||||
@@ -98,11 +80,15 @@ Install Hugo from a [prebuilt binary], package manager, or package repository. P
|
||||
|
||||
## Build from source
|
||||
|
||||
Hugo is available in two editions: standard and extended. With the extended edition you can:
|
||||
|
||||
- Encode to the WebP format when processing images. You can decode WebP images with either edition.
|
||||
- Transpile Sass to CSS using the embedded LibSass transpiler. The extended edition is not required to use the Dart Sass transpiler.
|
||||
|
||||
Prerequisites to build Hugo from source:
|
||||
|
||||
- Standard edition: Go 1.23.0 or later
|
||||
- Extended edition: Go 1.23.0 or later, and GCC
|
||||
- Extended/deploy edition: Go 1.23.0 or later, and GCC
|
||||
- Standard edition: Go 1.20 or later
|
||||
- Extended edition: Go 1.20 or later, and GCC
|
||||
|
||||
Build the standard edition:
|
||||
|
||||
@@ -116,12 +102,6 @@ Build the extended edition:
|
||||
CGO_ENABLED=1 go install -tags extended github.com/gohugoio/hugo@latest
|
||||
```
|
||||
|
||||
Build the extended/deploy edition:
|
||||
|
||||
```text
|
||||
CGO_ENABLED=1 go install -tags extended,withdeploy github.com/gohugoio/hugo@latest
|
||||
```
|
||||
|
||||
## Star History
|
||||
|
||||
[](https://star-history.com/#gohugoio/hugo&Timeline)
|
||||
@@ -169,9 +149,7 @@ Hugo stands on the shoulders of great open source libraries. Run `hugo env --log
|
||||
|
||||
```text
|
||||
github.com/BurntSushi/locker="v0.0.0-20171006230638-a6e239ea1c69"
|
||||
github.com/PuerkitoBio/goquery="v1.10.1"
|
||||
github.com/alecthomas/chroma/v2="v2.15.0"
|
||||
github.com/andybalholm/cascadia="v1.3.3"
|
||||
github.com/alecthomas/chroma/v2="v2.14.0"
|
||||
github.com/armon/go-radix="v1.0.1-0.20221118154546-54df44f2176c"
|
||||
github.com/bep/clocks="v0.5.0"
|
||||
github.com/bep/debounce="v1.2.0"
|
||||
@@ -180,78 +158,73 @@ github.com/bep/goat="v0.5.0"
|
||||
github.com/bep/godartsass/v2="v2.3.2"
|
||||
github.com/bep/golibsass="v1.2.0"
|
||||
github.com/bep/gowebp="v0.3.0"
|
||||
github.com/bep/imagemeta="v0.8.4"
|
||||
github.com/bep/imagemeta="v0.8.3"
|
||||
github.com/bep/lazycache="v0.7.0"
|
||||
github.com/bep/logg="v0.4.0"
|
||||
github.com/bep/mclib="v1.20400.20402"
|
||||
github.com/bep/overlayfs="v0.9.2"
|
||||
github.com/bep/simplecobra="v0.5.0"
|
||||
github.com/bep/simplecobra="v0.4.0"
|
||||
github.com/bep/tmc="v0.5.1"
|
||||
github.com/cespare/xxhash/v2="v2.3.0"
|
||||
github.com/clbanning/mxj/v2="v2.7.0"
|
||||
github.com/cli/safeexec="v1.0.1"
|
||||
github.com/cpuguy83/go-md2man/v2="v2.0.4"
|
||||
github.com/disintegration/gift="v1.2.1"
|
||||
github.com/dlclark/regexp2="v1.11.5"
|
||||
github.com/dop251/goja="v0.0.0-20250125213203-5ef83b82af17"
|
||||
github.com/evanw/esbuild="v0.24.2"
|
||||
github.com/dlclark/regexp2="v1.11.0"
|
||||
github.com/evanw/esbuild="v0.24.0"
|
||||
github.com/fatih/color="v1.18.0"
|
||||
github.com/frankban/quicktest="v1.14.6"
|
||||
github.com/fsnotify/fsnotify="v1.8.0"
|
||||
github.com/getkin/kin-openapi="v0.129.0"
|
||||
github.com/getkin/kin-openapi="v0.123.0"
|
||||
github.com/ghodss/yaml="v1.0.0"
|
||||
github.com/go-openapi/jsonpointer="v0.21.0"
|
||||
github.com/go-openapi/swag="v0.23.0"
|
||||
github.com/go-sourcemap/sourcemap="v2.1.4+incompatible"
|
||||
github.com/go-openapi/jsonpointer="v0.20.2"
|
||||
github.com/go-openapi/swag="v0.22.8"
|
||||
github.com/gobuffalo/flect="v1.0.3"
|
||||
github.com/gobwas/glob="v0.2.3"
|
||||
github.com/gohugoio/go-i18n/v2="v2.1.3-0.20230805085216-e63c13218d0e"
|
||||
github.com/gohugoio/hashstructure="v0.5.0"
|
||||
github.com/gohugoio/hashstructure="v0.1.0"
|
||||
github.com/gohugoio/httpcache="v0.7.0"
|
||||
github.com/gohugoio/hugo-goldmark-extensions/extras="v0.2.0"
|
||||
github.com/gohugoio/hugo-goldmark-extensions/passthrough="v0.3.0"
|
||||
github.com/gohugoio/locales="v0.14.0"
|
||||
github.com/gohugoio/localescompressed="v1.0.1"
|
||||
github.com/golang/freetype="v0.0.0-20170609003504-e2365dfdc4a0"
|
||||
github.com/google/go-cmp="v0.6.0"
|
||||
github.com/google/pprof="v0.0.0-20250208200701-d0013a598941"
|
||||
github.com/gorilla/websocket="v1.5.3"
|
||||
github.com/hairyhenderson/go-codeowners="v0.7.0"
|
||||
github.com/hashicorp/golang-lru/v2="v2.0.7"
|
||||
github.com/invopop/yaml="v0.2.0"
|
||||
github.com/jdkato/prose="v1.2.1"
|
||||
github.com/josharian/intern="v1.0.0"
|
||||
github.com/kr/pretty="v0.3.1"
|
||||
github.com/kr/text="v0.2.0"
|
||||
github.com/kyokomi/emoji/v2="v2.2.13"
|
||||
github.com/lucasb-eyer/go-colorful="v1.2.0"
|
||||
github.com/mailru/easyjson="v0.7.7"
|
||||
github.com/makeworld-the-better-one/dither/v2="v2.4.0"
|
||||
github.com/marekm4/color-extractor="v1.2.1"
|
||||
github.com/mattn/go-colorable="v0.1.13"
|
||||
github.com/mattn/go-isatty="v0.0.20"
|
||||
github.com/mattn/go-runewidth="v0.0.9"
|
||||
github.com/mazznoer/csscolorparser="v0.1.5"
|
||||
github.com/mitchellh/mapstructure="v1.5.1-0.20231216201459-8508981c8b6c"
|
||||
github.com/mohae/deepcopy="v0.0.0-20170929034955-c48cc78d4826"
|
||||
github.com/muesli/smartcrop="v0.3.0"
|
||||
github.com/niklasfasching/go-org="v1.7.0"
|
||||
github.com/oasdiff/yaml3="v0.0.0-20241210130736-a94c01f36349"
|
||||
github.com/oasdiff/yaml="v0.0.0-20241210131133-6b86fb107d80"
|
||||
github.com/olekukonko/tablewriter="v0.0.5"
|
||||
github.com/pbnjay/memory="v0.0.0-20210728143218-7b4eea64cf58"
|
||||
github.com/pelletier/go-toml/v2="v2.2.3"
|
||||
github.com/perimeterx/marshmallow="v1.1.5"
|
||||
github.com/pkg/browser="v0.0.0-20240102092130-5ac0b6a4141c"
|
||||
github.com/pkg/errors="v0.9.1"
|
||||
github.com/rivo/uniseg="v0.4.7"
|
||||
github.com/rogpeppe/go-internal="v1.13.1"
|
||||
github.com/russross/blackfriday/v2="v2.1.0"
|
||||
github.com/sass/dart-sass/compiler="1.81.0"
|
||||
github.com/sass/dart-sass/implementation="1.81.0"
|
||||
github.com/sass/dart-sass/protocol="3.1.0"
|
||||
github.com/sass/libsass="3.6.6"
|
||||
github.com/spf13/afero="v1.11.0"
|
||||
github.com/spf13/cast="v1.7.1"
|
||||
github.com/spf13/cobra="v1.8.1"
|
||||
github.com/spf13/fsync="v0.10.1"
|
||||
github.com/spf13/pflag="v1.0.6"
|
||||
github.com/spf13/pflag="v1.0.5"
|
||||
github.com/tdewolff/minify/v2="v2.20.37"
|
||||
github.com/tdewolff/parse/v2="v2.7.15"
|
||||
github.com/tetratelabs/wazero="v1.8.2"
|
||||
@@ -259,22 +232,18 @@ github.com/webmproject/libwebp="v1.3.2"
|
||||
github.com/yuin/goldmark-emoji="v1.0.4"
|
||||
github.com/yuin/goldmark="v1.7.8"
|
||||
go.uber.org/automaxprocs="v1.5.3"
|
||||
golang.org/x/crypto="v0.33.0"
|
||||
golang.org/x/exp="v0.0.0-20250210185358-939b2ce775ac"
|
||||
golang.org/x/image="v0.24.0"
|
||||
golang.org/x/mod="v0.23.0"
|
||||
golang.org/x/net="v0.35.0"
|
||||
golang.org/x/sync="v0.11.0"
|
||||
golang.org/x/sys="v0.30.0"
|
||||
golang.org/x/text="v0.22.0"
|
||||
golang.org/x/tools="v0.30.0"
|
||||
golang.org/x/xerrors="v0.0.0-20240903120638-7835f813f4da"
|
||||
gonum.org/v1/plot="v0.15.0"
|
||||
google.golang.org/protobuf="v1.36.5"
|
||||
golang.org/x/crypto="v0.31.0"
|
||||
golang.org/x/exp="v0.0.0-20221031165847-c99f073a8326"
|
||||
golang.org/x/image="v0.22.0"
|
||||
golang.org/x/mod="v0.22.0"
|
||||
golang.org/x/net="v0.33.0"
|
||||
golang.org/x/sync="v0.10.0"
|
||||
golang.org/x/sys="v0.28.0"
|
||||
golang.org/x/text="v0.21.0"
|
||||
golang.org/x/tools="v0.28.0"
|
||||
google.golang.org/protobuf="v1.35.2"
|
||||
gopkg.in/yaml.v2="v2.4.0"
|
||||
gopkg.in/yaml.v3="v3.0.1"
|
||||
oss.terrastruct.com/d2="v0.6.9"
|
||||
oss.terrastruct.com/util-go="v0.0.0-20241005222610-44c011a04896"
|
||||
rsc.io/qr="v0.2.0"
|
||||
software.sslmate.com/src/go-pkcs12="v0.2.0"
|
||||
```
|
||||
|
||||
Vendored
+5
-11
@@ -176,12 +176,11 @@ func (c *Cache) ClearMatching(predicatePartition func(k string, p PartitionManag
|
||||
}
|
||||
|
||||
// ClearOnRebuild prepares the cache for a new rebuild taking the given changeset into account.
|
||||
// predicate is optional and will clear any entry for which it returns true.
|
||||
func (c *Cache) ClearOnRebuild(predicate func(k, v any) bool, changeset ...identity.Identity) {
|
||||
func (c *Cache) ClearOnRebuild(changeset ...identity.Identity) {
|
||||
g := rungroup.Run[PartitionManager](context.Background(), rungroup.Config[PartitionManager]{
|
||||
NumWorkers: len(c.partitions),
|
||||
Handle: func(ctx context.Context, partition PartitionManager) error {
|
||||
partition.clearOnRebuild(predicate, changeset...)
|
||||
partition.clearOnRebuild(changeset...)
|
||||
return nil
|
||||
},
|
||||
})
|
||||
@@ -480,12 +479,7 @@ func (p *Partition[K, V]) clearMatching(predicate func(k, v any) bool) {
|
||||
})
|
||||
}
|
||||
|
||||
func (p *Partition[K, V]) clearOnRebuild(predicate func(k, v any) bool, changeset ...identity.Identity) {
|
||||
if predicate == nil {
|
||||
predicate = func(k, v any) bool {
|
||||
return false
|
||||
}
|
||||
}
|
||||
func (p *Partition[K, V]) clearOnRebuild(changeset ...identity.Identity) {
|
||||
opts := p.getOptions()
|
||||
if opts.ClearWhen == ClearNever {
|
||||
return
|
||||
@@ -531,7 +525,7 @@ func (p *Partition[K, V]) clearOnRebuild(predicate func(k, v any) bool, changese
|
||||
// Second pass needs to be done in a separate loop to catch any
|
||||
// elements marked as stale in the other partitions.
|
||||
p.c.DeleteFunc(func(key K, v V) bool {
|
||||
if predicate(key, v) || shouldDelete(key, v) {
|
||||
if shouldDelete(key, v) {
|
||||
p.trace.Log(
|
||||
logg.StringFunc(
|
||||
func() string {
|
||||
@@ -607,7 +601,7 @@ type PartitionManager interface {
|
||||
adjustMaxSize(addend int) int
|
||||
getMaxSize() int
|
||||
getOptions() OptionsPartition
|
||||
clearOnRebuild(predicate func(k, v any) bool, changeset ...identity.Identity)
|
||||
clearOnRebuild(changeset ...identity.Identity)
|
||||
clearMatching(predicate func(k, v any) bool)
|
||||
clearStale()
|
||||
}
|
||||
|
||||
Vendored
+6
-6
@@ -147,13 +147,13 @@ func TestClear(t *testing.T) {
|
||||
|
||||
c.Assert(cache.Keys(predicateAll), qt.HasLen, 4)
|
||||
|
||||
cache.ClearOnRebuild(nil)
|
||||
cache.ClearOnRebuild()
|
||||
|
||||
// Stale items are always cleared.
|
||||
c.Assert(cache.Keys(predicateAll), qt.HasLen, 2)
|
||||
|
||||
cache = newTestCache(t)
|
||||
cache.ClearOnRebuild(nil, identity.StringIdentity("changed"))
|
||||
cache.ClearOnRebuild(identity.StringIdentity("changed"))
|
||||
|
||||
c.Assert(cache.Keys(nil), qt.HasLen, 1)
|
||||
|
||||
@@ -191,16 +191,16 @@ func TestPanicInCreate(t *testing.T) {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := range 3 {
|
||||
for range 3 {
|
||||
for i := 0; i < 3; i++ {
|
||||
for j := 0; j < 3; j++ {
|
||||
c.Assert(willPanic(i), qt.PanicMatches, fmt.Sprintf("panic-%d", i))
|
||||
c.Assert(willErr(i), qt.ErrorMatches, fmt.Sprintf("error-%d", i))
|
||||
}
|
||||
}
|
||||
|
||||
// Test the same keys again without the panic.
|
||||
for i := range 3 {
|
||||
for range 3 {
|
||||
for i := 0; i < 3; i++ {
|
||||
for j := 0; j < 3; j++ {
|
||||
v, err := p1.GetOrCreate(fmt.Sprintf("panic-%d", i), func(key string) (testItem, error) {
|
||||
return testItem{
|
||||
name: key,
|
||||
|
||||
+3
-3
@@ -59,7 +59,7 @@ dir = ":resourceDir/_gen"
|
||||
caches, err := filecache.NewCaches(p)
|
||||
c.Assert(err, qt.IsNil)
|
||||
cache := caches[name]
|
||||
for i := range 10 {
|
||||
for i := 0; i < 10; i++ {
|
||||
id := fmt.Sprintf("i%d", i)
|
||||
cache.GetOrCreateBytes(id, func() ([]byte, error) {
|
||||
return []byte("abc"), nil
|
||||
@@ -74,7 +74,7 @@ dir = ":resourceDir/_gen"
|
||||
c.Assert(err, qt.IsNil)
|
||||
c.Assert(count, qt.Equals, 5, msg)
|
||||
|
||||
for i := range 10 {
|
||||
for i := 0; i < 10; i++ {
|
||||
id := fmt.Sprintf("i%d", i)
|
||||
v := cache.GetString(id)
|
||||
if i < 5 {
|
||||
@@ -97,7 +97,7 @@ dir = ":resourceDir/_gen"
|
||||
c.Assert(count, qt.Equals, 4)
|
||||
|
||||
// Now only the i5 should be left.
|
||||
for i := range 10 {
|
||||
for i := 0; i < 10; i++ {
|
||||
id := fmt.Sprintf("i%d", i)
|
||||
v := cache.GetString(id)
|
||||
if i != 5 {
|
||||
|
||||
Vendored
+3
-3
@@ -105,7 +105,7 @@ dir = ":cacheDir/c"
|
||||
}
|
||||
|
||||
for _, ca := range []*filecache.Cache{caches.ImageCache(), caches.AssetsCache(), caches.GetJSONCache(), caches.GetCSVCache()} {
|
||||
for range 2 {
|
||||
for i := 0; i < 2; i++ {
|
||||
info, r, err := ca.GetOrCreate("a", rf("abc"))
|
||||
c.Assert(err, qt.IsNil)
|
||||
c.Assert(r, qt.Not(qt.IsNil))
|
||||
@@ -193,11 +193,11 @@ dir = "/cache/c"
|
||||
|
||||
var wg sync.WaitGroup
|
||||
|
||||
for i := range 50 {
|
||||
for i := 0; i < 50; i++ {
|
||||
wg.Add(1)
|
||||
go func(i int) {
|
||||
defer wg.Done()
|
||||
for range 20 {
|
||||
for j := 0; j < 20; j++ {
|
||||
ca := caches.Get(cacheName)
|
||||
c.Assert(ca, qt.Not(qt.IsNil))
|
||||
filename, data := filenameData(i)
|
||||
|
||||
Vendored
+2
-13
@@ -42,7 +42,7 @@ var DefaultConfig = Config{
|
||||
|
||||
// Config holds the configuration for the HTTP cache.
|
||||
type Config struct {
|
||||
// Configures the HTTP cache behavior (RFC 9111).
|
||||
// Configures the HTTP cache behaviour (RFC 9111).
|
||||
// When this is not enabled for a resource, Hugo will go straight to the file cache.
|
||||
Cache Cache
|
||||
|
||||
@@ -52,7 +52,7 @@ type Config struct {
|
||||
}
|
||||
|
||||
type Cache struct {
|
||||
// Enable HTTP cache behavior (RFC 9111) for these resources.
|
||||
// Enable HTTP cache behaviour (RFC 9111) for these rsources.
|
||||
For GlobMatcher
|
||||
}
|
||||
|
||||
@@ -122,10 +122,6 @@ type GlobMatcher struct {
|
||||
Includes []string
|
||||
}
|
||||
|
||||
func (gm GlobMatcher) IsZero() bool {
|
||||
return len(gm.Includes) == 0 && len(gm.Excludes) == 0
|
||||
}
|
||||
|
||||
type ConfigCompiled struct {
|
||||
For predicate.P[string]
|
||||
PollConfigs []PollConfigCompiled
|
||||
@@ -159,9 +155,6 @@ func (p PollConfigCompiled) IsZero() bool {
|
||||
}
|
||||
|
||||
func (gm *GlobMatcher) CompilePredicate() (func(string) bool, error) {
|
||||
if gm.IsZero() {
|
||||
panic("no includes or excludes")
|
||||
}
|
||||
var p predicate.P[string]
|
||||
for _, include := range gm.Includes {
|
||||
g, err := glob.Compile(include, '/')
|
||||
@@ -210,9 +203,5 @@ func DecodeConfig(bcfg config.BaseConfig, m map[string]any) (Config, error) {
|
||||
return c, err
|
||||
}
|
||||
|
||||
if c.Cache.For.IsZero() {
|
||||
c.Cache.For = DefaultConfig.Cache.For
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
-31
@@ -22,8 +22,6 @@ import (
|
||||
)
|
||||
|
||||
func TestConfigCustom(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
files := `
|
||||
-- hugo.toml --
|
||||
[httpcache]
|
||||
@@ -53,8 +51,6 @@ includes = ["**gohugo.io**"]
|
||||
}
|
||||
|
||||
func TestConfigDefault(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
files := `
|
||||
-- hugo.toml --
|
||||
`
|
||||
@@ -66,30 +62,3 @@ func TestConfigDefault(t *testing.T) {
|
||||
b.Assert(compiled.For("https://gohugo.io/foo.jpg"), qt.IsFalse)
|
||||
b.Assert(compiled.PollConfigFor("https://gohugo.io/foo.jpg").Config.Disable, qt.IsTrue)
|
||||
}
|
||||
|
||||
func TestConfigPollsOnly(t *testing.T) {
|
||||
t.Parallel()
|
||||
files := `
|
||||
-- hugo.toml --
|
||||
[httpcache]
|
||||
[[httpcache.polls]]
|
||||
low = "5s"
|
||||
high = "32s"
|
||||
[httpcache.polls.for]
|
||||
includes = ["**gohugo.io**"]
|
||||
|
||||
|
||||
`
|
||||
|
||||
b := hugolib.Test(t, files)
|
||||
|
||||
compiled := b.H.Configs.Base.C.HTTPCache
|
||||
|
||||
b.Assert(compiled.For("https://gohugo.io/posts.json"), qt.IsFalse)
|
||||
b.Assert(compiled.For("https://gohugo.io/foo.jpg"), qt.IsFalse)
|
||||
|
||||
pc := compiled.PollConfigFor("https://gohugo.io/foo.jpg")
|
||||
b.Assert(pc.Config.Low, qt.Equals, 5*time.Second)
|
||||
b.Assert(pc.Config.High, qt.Equals, 32*time.Second)
|
||||
b.Assert(compiled.PollConfigFor("https://example.com/foo.jpg").IsZero(), qt.IsTrue)
|
||||
}
|
||||
|
||||
+7
-8
@@ -26,7 +26,6 @@ import (
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -103,7 +102,7 @@ func (c *Inspector) MethodsFromTypes(include []reflect.Type, exclude []reflect.T
|
||||
}
|
||||
|
||||
for _, t := range include {
|
||||
for i := range t.NumMethod() {
|
||||
for i := 0; i < t.NumMethod(); i++ {
|
||||
|
||||
m := t.Method(i)
|
||||
if excludes[m.Name] || seen[m.Name] {
|
||||
@@ -123,7 +122,7 @@ func (c *Inspector) MethodsFromTypes(include []reflect.Type, exclude []reflect.T
|
||||
|
||||
method := Method{Owner: t, OwnerName: ownerName, Name: m.Name}
|
||||
|
||||
for i := range numIn {
|
||||
for i := 0; i < numIn; i++ {
|
||||
in := m.Type.In(i)
|
||||
|
||||
name, pkg := nameAndPackage(in)
|
||||
@@ -138,7 +137,7 @@ func (c *Inspector) MethodsFromTypes(include []reflect.Type, exclude []reflect.T
|
||||
numOut := m.Type.NumOut()
|
||||
|
||||
if numOut > 0 {
|
||||
for i := range numOut {
|
||||
for i := 0; i < numOut; i++ {
|
||||
out := m.Type.Out(i)
|
||||
name, pkg := nameAndPackage(out)
|
||||
|
||||
@@ -305,7 +304,7 @@ func (m Method) inOutStr() string {
|
||||
}
|
||||
|
||||
args := make([]string, len(m.In))
|
||||
for i := range args {
|
||||
for i := 0; i < len(args); i++ {
|
||||
args[i] = fmt.Sprintf("arg%d", i)
|
||||
}
|
||||
return "(" + strings.Join(args, ", ") + ")"
|
||||
@@ -317,7 +316,7 @@ func (m Method) inStr() string {
|
||||
}
|
||||
|
||||
args := make([]string, len(m.In))
|
||||
for i := range args {
|
||||
for i := 0; i < len(args); i++ {
|
||||
args[i] = fmt.Sprintf("arg%d %s", i, m.In[i])
|
||||
}
|
||||
return "(" + strings.Join(args, ", ") + ")"
|
||||
@@ -340,7 +339,7 @@ func (m Method) outStrNamed() string {
|
||||
}
|
||||
|
||||
outs := make([]string, len(m.Out))
|
||||
for i := range outs {
|
||||
for i := 0; i < len(outs); i++ {
|
||||
outs[i] = fmt.Sprintf("o%d %s", i, m.Out[i])
|
||||
}
|
||||
|
||||
@@ -436,7 +435,7 @@ func (m Methods) ToMarshalJSON(receiver, pkgPath string, excludes ...string) (st
|
||||
// Exclude self
|
||||
for i, pkgImp := range pkgImports {
|
||||
if pkgImp == pkgPath {
|
||||
pkgImports = slices.Delete(pkgImports, i, i+1)
|
||||
pkgImports = append(pkgImports[:i], pkgImports[i+1:]...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,8 +101,8 @@ type configKey struct {
|
||||
|
||||
// This is the root command.
|
||||
type rootCommand struct {
|
||||
Printf func(format string, v ...any)
|
||||
Println func(a ...any)
|
||||
Printf func(format string, v ...interface{})
|
||||
Println func(a ...interface{})
|
||||
StdOut io.Writer
|
||||
StdErr io.Writer
|
||||
|
||||
@@ -431,12 +431,12 @@ func (r *rootCommand) PreRun(cd, runner *simplecobra.Commandeer) error {
|
||||
// Used by mkcert (server).
|
||||
log.SetOutput(r.StdOut)
|
||||
|
||||
r.Printf = func(format string, v ...any) {
|
||||
r.Printf = func(format string, v ...interface{}) {
|
||||
if !r.quiet {
|
||||
fmt.Fprintf(r.StdOut, format, v...)
|
||||
}
|
||||
}
|
||||
r.Println = func(a ...any) {
|
||||
r.Println = func(a ...interface{}) {
|
||||
if !r.quiet {
|
||||
fmt.Fprintln(r.StdOut, a...)
|
||||
}
|
||||
@@ -448,7 +448,7 @@ func (r *rootCommand) PreRun(cd, runner *simplecobra.Commandeer) error {
|
||||
return err
|
||||
}
|
||||
// Set up the global logger early to allow info deprecations during config load.
|
||||
loggers.SetGlobalLogger(r.logger)
|
||||
loggers.InitGlobalLogger(r.logger.Level(), false)
|
||||
|
||||
r.changesFromBuild = make(chan []identity.Identity, 10)
|
||||
|
||||
|
||||
+1
-1
@@ -90,7 +90,7 @@ func (c *configCommand) Run(ctx context.Context, cd *simplecobra.Commandeer, arg
|
||||
os.Stdout.Write(buf.Bytes())
|
||||
default:
|
||||
// Decode the JSON to a map[string]interface{} and then unmarshal it again to the correct format.
|
||||
var m map[string]any
|
||||
var m map[string]interface{}
|
||||
if err := json.Unmarshal(buf.Bytes(), &m); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
//go:build withdeploy
|
||||
// +build withdeploy
|
||||
|
||||
package commands
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
//go:build !withdeploy
|
||||
// +build !withdeploy
|
||||
|
||||
// Copyright 2024 The Hugo Authors. All rights reserved.
|
||||
//
|
||||
|
||||
+3
-8
@@ -21,7 +21,6 @@ import (
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/alecthomas/chroma/v2"
|
||||
@@ -61,10 +60,6 @@ func newGenCommand() *genCommand {
|
||||
See https://xyproto.github.io/splash/docs/all.html for a preview of the available styles`,
|
||||
|
||||
run: func(ctx context.Context, cd *simplecobra.Commandeer, r *rootCommand, args []string) error {
|
||||
style = strings.ToLower(style)
|
||||
if !slices.Contains(styles.Names(), style) {
|
||||
return fmt.Errorf("invalid style: %s", style)
|
||||
}
|
||||
builder := styles.Get(style).Builder()
|
||||
if highlightStyle != "" {
|
||||
builder.Add(chroma.LineHighlight, highlightStyle)
|
||||
@@ -149,7 +144,7 @@ url: %s
|
||||
|
||||
return &simpleCommand{
|
||||
name: "doc",
|
||||
short: "Generate Markdown documentation for the Hugo CLI",
|
||||
short: "Generate Markdown documentation for the Hugo CLI.",
|
||||
long: `Generate Markdown documentation for the Hugo CLI.
|
||||
This command is, mostly, used to create up-to-date documentation
|
||||
of Hugo's command-line interface for https://gohugo.io/.
|
||||
@@ -201,7 +196,7 @@ url: %s
|
||||
newDocsHelper := func() simplecobra.Commander {
|
||||
return &simpleCommand{
|
||||
name: "docshelper",
|
||||
short: "Generate some data files for the Hugo docs",
|
||||
short: "Generate some data files for the Hugo docs.",
|
||||
|
||||
run: func(ctx context.Context, cd *simplecobra.Commandeer, r *rootCommand, args []string) error {
|
||||
r.Println("Generate docs data to", docsHelperTarget)
|
||||
@@ -222,7 +217,7 @@ url: %s
|
||||
}
|
||||
|
||||
// Decode the JSON to a map[string]interface{} and then unmarshal it again to the correct format.
|
||||
var m map[string]any
|
||||
var m map[string]interface{}
|
||||
if err := json.Unmarshal(buf.Bytes(), &m); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
+16
-14
@@ -663,20 +663,7 @@ func (c *hugoBuilder) handleEvents(watcher *watcher.Batcher,
|
||||
var n int
|
||||
for _, ev := range evs {
|
||||
keep := true
|
||||
// Write and rename operations are often followed by CHMOD.
|
||||
// There may be valid use cases for rebuilding the site on CHMOD,
|
||||
// but that will require more complex logic than this simple conditional.
|
||||
// On OS X this seems to be related to Spotlight, see:
|
||||
// https://github.com/go-fsnotify/fsnotify/issues/15
|
||||
// A workaround is to put your site(s) on the Spotlight exception list,
|
||||
// but that may be a little mysterious for most end users.
|
||||
// So, for now, we skip reload on CHMOD.
|
||||
// We do have to check for WRITE though. On slower laptops a Chmod
|
||||
// could be aggregated with other important events, and we still want
|
||||
// to rebuild on those
|
||||
if ev.Op == fsnotify.Chmod {
|
||||
keep = false
|
||||
} else if ev.Has(fsnotify.Create) || ev.Has(fsnotify.Write) {
|
||||
if ev.Has(fsnotify.Create) || ev.Has(fsnotify.Write) {
|
||||
if _, err := os.Stat(ev.Name); err != nil {
|
||||
keep = false
|
||||
}
|
||||
@@ -818,6 +805,21 @@ func (c *hugoBuilder) handleEvents(watcher *watcher.Batcher,
|
||||
continue
|
||||
}
|
||||
|
||||
// Write and rename operations are often followed by CHMOD.
|
||||
// There may be valid use cases for rebuilding the site on CHMOD,
|
||||
// but that will require more complex logic than this simple conditional.
|
||||
// On OS X this seems to be related to Spotlight, see:
|
||||
// https://github.com/go-fsnotify/fsnotify/issues/15
|
||||
// A workaround is to put your site(s) on the Spotlight exception list,
|
||||
// but that may be a little mysterious for most end users.
|
||||
// So, for now, we skip reload on CHMOD.
|
||||
// We do have to check for WRITE though. On slower laptops a Chmod
|
||||
// could be aggregated with other important events, and we still want
|
||||
// to rebuild on those
|
||||
if ev.Op&(fsnotify.Chmod|fsnotify.Write|fsnotify.Create) == fsnotify.Chmod {
|
||||
continue
|
||||
}
|
||||
|
||||
walkAdder := func(path string, f hugofs.FileMetaInfo) error {
|
||||
if f.IsDir() {
|
||||
c.r.logger.Println("adding created directory to watchlist", path)
|
||||
|
||||
+14
-14
@@ -44,16 +44,16 @@ func newModCommands() *modCommands {
|
||||
|
||||
npmCommand := &simpleCommand{
|
||||
name: "npm",
|
||||
short: "Various npm helpers",
|
||||
short: "Various npm helpers.",
|
||||
long: `Various npm (Node package manager) helpers.`,
|
||||
commands: []simplecobra.Commander{
|
||||
&simpleCommand{
|
||||
name: "pack",
|
||||
short: "Experimental: Prepares and writes a composite package.json file for your project",
|
||||
short: "Experimental: Prepares and writes a composite package.json file for your project.",
|
||||
long: `Prepares and writes a composite package.json file for your project.
|
||||
|
||||
On first run it creates a "package.hugo.json" in the project root if not already there. This file will be used as a template file
|
||||
with the base dependency set.
|
||||
with the base dependency set.
|
||||
|
||||
This set will be merged with all "package.hugo.json" files found in the dependency tree, picking the version closest to the project.
|
||||
|
||||
@@ -80,12 +80,12 @@ so this may/will change in future versions of Hugo.
|
||||
commands: []simplecobra.Commander{
|
||||
&simpleCommand{
|
||||
name: "init",
|
||||
short: "Initialize this project as a Hugo Module",
|
||||
short: "Initialize this project as a Hugo Module.",
|
||||
long: `Initialize this project as a Hugo Module.
|
||||
It will try to guess the module path, but you may help by passing it as an argument, e.g:
|
||||
|
||||
|
||||
hugo mod init github.com/gohugoio/testshortcodes
|
||||
|
||||
|
||||
Note that Hugo Modules supports multi-module projects, so you can initialize a Hugo Module
|
||||
inside a subfolder on GitHub, as one example.
|
||||
`,
|
||||
@@ -111,7 +111,7 @@ so this may/will change in future versions of Hugo.
|
||||
},
|
||||
&simpleCommand{
|
||||
name: "verify",
|
||||
short: "Verify dependencies",
|
||||
short: "Verify dependencies.",
|
||||
long: `Verify checks that the dependencies of the current module, which are stored in a local downloaded source cache, have not been modified since being downloaded.`,
|
||||
withc: func(cmd *cobra.Command, r *rootCommand) {
|
||||
cmd.ValidArgsFunction = cobra.NoFileCompletions
|
||||
@@ -129,7 +129,7 @@ so this may/will change in future versions of Hugo.
|
||||
},
|
||||
&simpleCommand{
|
||||
name: "graph",
|
||||
short: "Print a module dependency graph",
|
||||
short: "Print a module dependency graph.",
|
||||
long: `Print a module dependency graph with information about module status (disabled, vendored).
|
||||
Note that for vendored modules, that is the version listed and not the one from go.mod.
|
||||
`,
|
||||
@@ -149,7 +149,7 @@ Note that for vendored modules, that is the version listed and not the one from
|
||||
},
|
||||
&simpleCommand{
|
||||
name: "clean",
|
||||
short: "Delete the Hugo Module cache for the current project",
|
||||
short: "Delete the Hugo Module cache for the current project.",
|
||||
long: `Delete the Hugo Module cache for the current project.`,
|
||||
withc: func(cmd *cobra.Command, r *rootCommand) {
|
||||
cmd.ValidArgsFunction = cobra.NoFileCompletions
|
||||
@@ -175,7 +175,7 @@ Note that for vendored modules, that is the version listed and not the one from
|
||||
},
|
||||
&simpleCommand{
|
||||
name: "tidy",
|
||||
short: "Remove unused entries in go.mod and go.sum",
|
||||
short: "Remove unused entries in go.mod and go.sum.",
|
||||
withc: func(cmd *cobra.Command, r *rootCommand) {
|
||||
cmd.ValidArgsFunction = cobra.NoFileCompletions
|
||||
applyLocalFlagsBuildConfig(cmd, r)
|
||||
@@ -190,7 +190,7 @@ Note that for vendored modules, that is the version listed and not the one from
|
||||
},
|
||||
&simpleCommand{
|
||||
name: "vendor",
|
||||
short: "Vendor all module dependencies into the _vendor directory",
|
||||
short: "Vendor all module dependencies into the _vendor directory.",
|
||||
long: `Vendor all module dependencies into the _vendor directory.
|
||||
If a module is vendored, that is where Hugo will look for it's dependencies.
|
||||
`,
|
||||
@@ -209,16 +209,16 @@ Note that for vendored modules, that is the version listed and not the one from
|
||||
|
||||
&simpleCommand{
|
||||
name: "get",
|
||||
short: "Resolves dependencies in your current Hugo project",
|
||||
short: "Resolves dependencies in your current Hugo Project.",
|
||||
long: `
|
||||
Resolves dependencies in your current Hugo project.
|
||||
Resolves dependencies in your current Hugo Project.
|
||||
|
||||
Some examples:
|
||||
|
||||
Install the latest version possible for a given module:
|
||||
|
||||
hugo mod get github.com/gohugoio/testshortcodes
|
||||
|
||||
|
||||
Install a specific version:
|
||||
|
||||
hugo mod get github.com/gohugoio/testshortcodes@v0.3.0
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ func newReleaseCommand() simplecobra.Commander {
|
||||
|
||||
return &simpleCommand{
|
||||
name: "release",
|
||||
short: "Release a new version of Hugo",
|
||||
short: "Release a new version of Hugo.",
|
||||
run: func(ctx context.Context, cd *simplecobra.Commandeer, r *rootCommand, args []string) error {
|
||||
rel, err := releaser.New(skipPush, try, step)
|
||||
if err != nil {
|
||||
|
||||
+57
-79
@@ -65,7 +65,6 @@ import (
|
||||
"github.com/spf13/fsync"
|
||||
"golang.org/x/sync/errgroup"
|
||||
"golang.org/x/sync/semaphore"
|
||||
"maps"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -85,10 +84,6 @@ const (
|
||||
configChangeGoWork = "go work file"
|
||||
)
|
||||
|
||||
const (
|
||||
hugoHeaderRedirect = "X-Hugo-Redirect"
|
||||
)
|
||||
|
||||
func newHugoBuilder(r *rootCommand, s *serverCommand, onConfigLoaded ...func(reloaded bool) error) *hugoBuilder {
|
||||
var visitedURLs *types.EvictingQueue[string]
|
||||
if s != nil && !s.disableFastRender {
|
||||
@@ -120,7 +115,7 @@ func newServerCommand() *serverCommand {
|
||||
commands: []simplecobra.Commander{
|
||||
&simpleCommand{
|
||||
name: "trust",
|
||||
short: "Install the local CA in the system trust store",
|
||||
short: "Install the local CA in the system trust store.",
|
||||
run: func(ctx context.Context, cd *simplecobra.Commandeer, r *rootCommand, args []string) error {
|
||||
action := "-install"
|
||||
if uninstall {
|
||||
@@ -196,7 +191,9 @@ func (f *fileChangeDetector) PrepareNew() {
|
||||
}
|
||||
|
||||
f.prev = make(map[string]uint64)
|
||||
maps.Copy(f.prev, f.current)
|
||||
for k, v := range f.current {
|
||||
f.prev[k] = v
|
||||
}
|
||||
f.current = make(map[string]uint64)
|
||||
}
|
||||
|
||||
@@ -310,65 +307,67 @@ func (f *fileServer) createEndpoint(i int) (*http.ServeMux, net.Listener, string
|
||||
w.Header().Set(header.Key, header.Value)
|
||||
}
|
||||
|
||||
if canRedirect(requestURI, r) {
|
||||
if redirect := serverConfig.MatchRedirect(requestURI, r.Header); !redirect.IsZero() {
|
||||
doRedirect := true
|
||||
// This matches Netlify's behavior and is needed for SPA behavior.
|
||||
// See https://docs.netlify.com/routing/redirects/rewrites-proxies/
|
||||
if !redirect.Force {
|
||||
path := filepath.Clean(strings.TrimPrefix(requestURI, baseURL.Path()))
|
||||
if root != "" {
|
||||
path = filepath.Join(root, path)
|
||||
}
|
||||
var fs afero.Fs
|
||||
f.c.withConf(func(conf *commonConfig) {
|
||||
fs = conf.fs.PublishDirServer
|
||||
})
|
||||
|
||||
fi, err := fs.Stat(path)
|
||||
|
||||
if err == nil {
|
||||
if fi.IsDir() {
|
||||
// There will be overlapping directories, so we
|
||||
// need to check for a file.
|
||||
_, err = fs.Stat(filepath.Join(path, "index.html"))
|
||||
doRedirect = err != nil
|
||||
} else {
|
||||
doRedirect = false
|
||||
}
|
||||
}
|
||||
if redirect := serverConfig.MatchRedirect(requestURI); !redirect.IsZero() {
|
||||
// fullName := filepath.Join(dir, filepath.FromSlash(path.Clean("/"+name)))
|
||||
doRedirect := true
|
||||
// This matches Netlify's behavior and is needed for SPA behavior.
|
||||
// See https://docs.netlify.com/routing/redirects/rewrites-proxies/
|
||||
if !redirect.Force {
|
||||
path := filepath.Clean(strings.TrimPrefix(requestURI, baseURL.Path()))
|
||||
if root != "" {
|
||||
path = filepath.Join(root, path)
|
||||
}
|
||||
var fs afero.Fs
|
||||
f.c.withConf(func(conf *commonConfig) {
|
||||
fs = conf.fs.PublishDirServer
|
||||
})
|
||||
|
||||
if doRedirect {
|
||||
w.Header().Set(hugoHeaderRedirect, "true")
|
||||
switch redirect.Status {
|
||||
case 404:
|
||||
w.WriteHeader(404)
|
||||
file, err := fs.Open(strings.TrimPrefix(redirect.To, baseURL.Path()))
|
||||
if err == nil {
|
||||
defer file.Close()
|
||||
io.Copy(w, file)
|
||||
} else {
|
||||
fmt.Fprintln(w, "<h1>Page Not Found</h1>")
|
||||
}
|
||||
return
|
||||
case 200:
|
||||
if r2 := f.rewriteRequest(r, strings.TrimPrefix(redirect.To, baseURL.Path())); r2 != nil {
|
||||
requestURI = redirect.To
|
||||
r = r2
|
||||
}
|
||||
default:
|
||||
w.Header().Set("Content-Type", "")
|
||||
http.Redirect(w, r, redirect.To, redirect.Status)
|
||||
return
|
||||
fi, err := fs.Stat(path)
|
||||
|
||||
if err == nil {
|
||||
if fi.IsDir() {
|
||||
// There will be overlapping directories, so we
|
||||
// need to check for a file.
|
||||
_, err = fs.Stat(filepath.Join(path, "index.html"))
|
||||
doRedirect = err != nil
|
||||
} else {
|
||||
doRedirect = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if doRedirect {
|
||||
switch redirect.Status {
|
||||
case 404:
|
||||
w.WriteHeader(404)
|
||||
file, err := fs.Open(strings.TrimPrefix(redirect.To, baseURL.Path()))
|
||||
if err == nil {
|
||||
defer file.Close()
|
||||
io.Copy(w, file)
|
||||
} else {
|
||||
fmt.Fprintln(w, "<h1>Page Not Found</h1>")
|
||||
}
|
||||
return
|
||||
case 200:
|
||||
if r2 := f.rewriteRequest(r, strings.TrimPrefix(redirect.To, baseURL.Path())); r2 != nil {
|
||||
requestURI = redirect.To
|
||||
r = r2
|
||||
}
|
||||
default:
|
||||
w.Header().Set("Content-Type", "")
|
||||
http.Redirect(w, r, redirect.To, redirect.Status)
|
||||
return
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if f.c.fastRenderMode && f.c.errState.buildErr() == nil {
|
||||
if isNavigation(requestURI, r) {
|
||||
// Sec-Fetch-Mode should be sent by all recent browser versions, see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Sec-Fetch-Mode#navigate
|
||||
// Fall back to the file extension if not set.
|
||||
// The main take here is that we don't want to have CSS/JS files etc. partake in this logic.
|
||||
if r.Header.Get("Sec-Fetch-Mode") == "navigate" || strings.HasSuffix(requestURI, "/") || strings.HasSuffix(requestURI, "html") || strings.HasSuffix(requestURI, "htm") {
|
||||
if !f.c.visitedURLs.Contains(requestURI) {
|
||||
// If not already on stack, re-render that single page.
|
||||
if err := f.c.partialReRender(requestURI); err != nil {
|
||||
@@ -758,7 +757,7 @@ func (c *serverCommand) createServerPorts(cd *simplecobra.Commandeer) error {
|
||||
c.serverPorts = make([]serverPortListener, len(conf.configs.Languages))
|
||||
}
|
||||
currentServerPort := c.serverPort
|
||||
for i := range c.serverPorts {
|
||||
for i := 0; i < len(c.serverPorts); i++ {
|
||||
l, err := net.Listen("tcp", net.JoinHostPort(c.serverInterface, strconv.Itoa(currentServerPort)))
|
||||
if err == nil {
|
||||
c.serverPorts[i] = serverPortListener{ln: l, p: currentServerPort}
|
||||
@@ -1234,24 +1233,3 @@ func formatByteCount(b uint64) string {
|
||||
return fmt.Sprintf("%.1f %cB",
|
||||
float64(b)/float64(div), "kMGTPE"[exp])
|
||||
}
|
||||
|
||||
func canRedirect(requestURIWithoutQuery string, r *http.Request) bool {
|
||||
if r.Header.Get(hugoHeaderRedirect) != "" {
|
||||
return false
|
||||
}
|
||||
return isNavigation(requestURIWithoutQuery, r)
|
||||
}
|
||||
|
||||
// Sec-Fetch-Mode should be sent by all recent browser versions, see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Sec-Fetch-Mode#navigate
|
||||
// Fall back to the file extension if not set.
|
||||
// The main take here is that we don't want to have CSS/JS files etc. partake in this logic.
|
||||
func isNavigation(requestURIWithoutQuery string, r *http.Request) bool {
|
||||
return r.Header.Get("Sec-Fetch-Mode") == "navigate" || isPropablyHTMLRequest(requestURIWithoutQuery)
|
||||
}
|
||||
|
||||
func isPropablyHTMLRequest(requestURIWithoutQuery string) bool {
|
||||
if strings.HasSuffix(requestURIWithoutQuery, "/") || strings.HasSuffix(requestURIWithoutQuery, "html") || strings.HasSuffix(requestURIWithoutQuery, "htm") {
|
||||
return true
|
||||
}
|
||||
return !strings.Contains(requestURIWithoutQuery, ".")
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ func appendToInterfaceSliceFromValues(slice1, slice2 reflect.Value) ([]any, erro
|
||||
tos = append(tos, nil)
|
||||
continue
|
||||
}
|
||||
for i := range slice.Len() {
|
||||
for i := 0; i < slice.Len(); i++ {
|
||||
tos = append(tos, slice.Index(i).Interface())
|
||||
}
|
||||
}
|
||||
@@ -128,7 +128,7 @@ func appendToInterfaceSliceFromValues(slice1, slice2 reflect.Value) ([]any, erro
|
||||
func appendToInterfaceSlice(tov reflect.Value, from ...any) ([]any, error) {
|
||||
var tos []any
|
||||
|
||||
for i := range tov.Len() {
|
||||
for i := 0; i < tov.Len(); i++ {
|
||||
tos = append(tos, tov.Index(i).Interface())
|
||||
}
|
||||
|
||||
|
||||
@@ -13,8 +13,6 @@
|
||||
|
||||
package collections
|
||||
|
||||
import "slices"
|
||||
|
||||
import "sync"
|
||||
|
||||
// Stack is a simple LIFO stack that is safe for concurrent use.
|
||||
@@ -75,7 +73,7 @@ func (s *Stack[T]) DrainMatching(predicate func(T) bool) []T {
|
||||
for i := len(s.items) - 1; i >= 0; i-- {
|
||||
if predicate(s.items[i]) {
|
||||
items = append(items, s.items[i])
|
||||
s.items = slices.Delete(s.items, i, i+1)
|
||||
s.items = append(s.items[:i], s.items[i+1:]...)
|
||||
}
|
||||
}
|
||||
return items
|
||||
|
||||
@@ -37,12 +37,12 @@ func TestXxHashFromReaderPara(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
for i := range 10 {
|
||||
for i := 0; i < 10; i++ {
|
||||
i := i
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for j := range 100 {
|
||||
for j := 0; j < 100; j++ {
|
||||
s := strings.Repeat("Hello ", i+j+1*42)
|
||||
r := strings.NewReader(s)
|
||||
got, size, err := XXHashFromReader(r)
|
||||
@@ -144,8 +144,8 @@ func BenchmarkHashString(b *testing.B) {
|
||||
}
|
||||
|
||||
func BenchmarkHashMap(b *testing.B) {
|
||||
m := map[string]any{}
|
||||
for i := range 1000 {
|
||||
m := map[string]interface{}{}
|
||||
for i := 0; i < 1000; i++ {
|
||||
m[fmt.Sprintf("key%d", i)] = i
|
||||
}
|
||||
|
||||
|
||||
@@ -152,7 +152,10 @@ func locateError(r io.Reader, le FileError, matches LineMatcherFn) *ErrorContext
|
||||
}
|
||||
|
||||
if ectx.Position.LineNumber > 0 {
|
||||
low := max(ectx.Position.LineNumber-3, 0)
|
||||
low := ectx.Position.LineNumber - 3
|
||||
if low < 0 {
|
||||
low = 0
|
||||
}
|
||||
|
||||
if ectx.Position.LineNumber > 2 {
|
||||
ectx.LinesPos = 2
|
||||
@@ -160,7 +163,10 @@ func locateError(r io.Reader, le FileError, matches LineMatcherFn) *ErrorContext
|
||||
ectx.LinesPos = ectx.Position.LineNumber - 1
|
||||
}
|
||||
|
||||
high := min(ectx.Position.LineNumber+2, len(lines))
|
||||
high := ectx.Position.LineNumber + 2
|
||||
if high > len(lines) {
|
||||
high = len(lines)
|
||||
}
|
||||
|
||||
ectx.Lines = lines[low:high]
|
||||
|
||||
|
||||
@@ -74,16 +74,6 @@ func IsTruthful(in any) bool {
|
||||
}
|
||||
}
|
||||
|
||||
// IsMap reports whether v is a map.
|
||||
func IsMap(v any) bool {
|
||||
return reflect.ValueOf(v).Kind() == reflect.Map
|
||||
}
|
||||
|
||||
// IsSlice reports whether v is a slice.
|
||||
func IsSlice(v any) bool {
|
||||
return reflect.ValueOf(v).Kind() == reflect.Slice
|
||||
}
|
||||
|
||||
var zeroType = reflect.TypeOf((*types.Zeroer)(nil)).Elem()
|
||||
|
||||
// IsTruthfulValue returns whether the given value has a meaningful truth value.
|
||||
@@ -245,7 +235,7 @@ func ToSliceAny(v any) ([]any, bool) {
|
||||
vvv := reflect.ValueOf(v)
|
||||
if vvv.Kind() == reflect.Slice {
|
||||
out := make([]any, vvv.Len())
|
||||
for i := range vvv.Len() {
|
||||
for i := 0; i < vvv.Len(); i++ {
|
||||
out[i] = vvv.Index(i).Interface()
|
||||
}
|
||||
return out, true
|
||||
|
||||
@@ -20,7 +20,6 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/gohugoio/hugo/compare"
|
||||
"slices"
|
||||
)
|
||||
|
||||
var _ compare.Eqer = StringEqualFold("")
|
||||
@@ -51,7 +50,12 @@ func (s StringEqualFold) Eq(s2 any) bool {
|
||||
|
||||
// EqualAny returns whether a string is equal to any of the given strings.
|
||||
func EqualAny(a string, b ...string) bool {
|
||||
return slices.Contains(b, a)
|
||||
for _, s := range b {
|
||||
if a == s {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// regexpCache represents a cache of regexp objects protected by a mutex.
|
||||
@@ -99,7 +103,12 @@ func GetOrCompileRegexp(pattern string) (re *regexp.Regexp, err error) {
|
||||
// InSlice checks if a string is an element of a slice of strings
|
||||
// and returns a boolean value.
|
||||
func InSlice(arr []string, el string) bool {
|
||||
return slices.Contains(arr, el)
|
||||
for _, v := range arr {
|
||||
if v == el {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// InSlicEqualFold checks if a string is an element of a slice of strings
|
||||
|
||||
@@ -46,7 +46,7 @@ func TestHasBytesWriter(t *testing.T) {
|
||||
return strings.Repeat("ab cfo", r.Intn(33))
|
||||
}
|
||||
|
||||
for range 22 {
|
||||
for i := 0; i < 22; i++ {
|
||||
h, w := neww()
|
||||
fmt.Fprint(w, rndStr()+"abc __foobar"+rndStr())
|
||||
c.Assert(h.Patterns[0].Match, qt.Equals, true)
|
||||
|
||||
+5
-11
@@ -414,17 +414,11 @@ func Deprecate(item, alternative string, version string) {
|
||||
DeprecateLevel(item, alternative, version, level)
|
||||
}
|
||||
|
||||
// DeprecateLevelMin informs about a deprecation starting at the given version, but with a minimum log level.
|
||||
func DeprecateLevelMin(item, alternative string, version string, minLevel logg.Level) {
|
||||
level := max(deprecationLogLevelFromVersion(version), minLevel)
|
||||
DeprecateLevel(item, alternative, version, level)
|
||||
}
|
||||
|
||||
// DeprecateLevel informs about a deprecation logging at the given level.
|
||||
func DeprecateLevel(item, alternative, version string, level logg.Level) {
|
||||
var msg string
|
||||
if level == logg.LevelError {
|
||||
msg = fmt.Sprintf("%s was deprecated in Hugo %s and subsequently removed. %s", item, version, alternative)
|
||||
msg = fmt.Sprintf("%s was deprecated in Hugo %s and will be removed in Hugo %s. %s", item, version, CurrentVersion.Next().ReleaseVersion(), alternative)
|
||||
} else {
|
||||
msg = fmt.Sprintf("%s was deprecated in Hugo %s and will be removed in a future release. %s", item, version, alternative)
|
||||
}
|
||||
@@ -440,11 +434,11 @@ func deprecationLogLevelFromVersion(ver string) logg.Level {
|
||||
to := CurrentVersion
|
||||
minorDiff := to.Minor - from.Minor
|
||||
switch {
|
||||
case minorDiff >= 15:
|
||||
// Start failing the build after about 15 months.
|
||||
case minorDiff >= 12:
|
||||
// Start failing the build after about a year.
|
||||
return logg.LevelError
|
||||
case minorDiff >= 3:
|
||||
// Start printing warnings after about 3 months.
|
||||
case minorDiff >= 6:
|
||||
// Start printing warnings after about six months.
|
||||
return logg.LevelWarn
|
||||
default:
|
||||
return logg.LevelInfo
|
||||
|
||||
@@ -57,11 +57,11 @@ func TestDeprecationLogLevelFromVersion(t *testing.T) {
|
||||
c.Assert(deprecationLogLevelFromVersion("0.55.0"), qt.Equals, logg.LevelError)
|
||||
ver := CurrentVersion
|
||||
c.Assert(deprecationLogLevelFromVersion(ver.String()), qt.Equals, logg.LevelInfo)
|
||||
ver.Minor -= 3
|
||||
ver.Minor -= 1
|
||||
c.Assert(deprecationLogLevelFromVersion(ver.String()), qt.Equals, logg.LevelInfo)
|
||||
ver.Minor -= 6
|
||||
c.Assert(deprecationLogLevelFromVersion(ver.String()), qt.Equals, logg.LevelWarn)
|
||||
ver.Minor -= 4
|
||||
c.Assert(deprecationLogLevelFromVersion(ver.String()), qt.Equals, logg.LevelWarn)
|
||||
ver.Minor -= 13
|
||||
ver.Minor -= 6
|
||||
c.Assert(deprecationLogLevelFromVersion(ver.String()), qt.Equals, logg.LevelError)
|
||||
|
||||
// Added just to find the threshold for where we can remove deprecated items.
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
//go:build extended
|
||||
// +build extended
|
||||
|
||||
package hugo
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
//go:build !extended
|
||||
// +build !extended
|
||||
|
||||
package hugo
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
//go:build withdeploy
|
||||
// +build withdeploy
|
||||
|
||||
package hugo
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
//go:build !withdeploy
|
||||
// +build !withdeploy
|
||||
|
||||
package hugo
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ package hugo
|
||||
// This should be the only one.
|
||||
var CurrentVersion = Version{
|
||||
Major: 0,
|
||||
Minor: 145,
|
||||
Minor: 143,
|
||||
PatchLevel: 0,
|
||||
Suffix: "",
|
||||
Suffix: "-DEV",
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ func TestLogDistinct(t *testing.T) {
|
||||
|
||||
l := loggers.New(opts)
|
||||
|
||||
for range 10 {
|
||||
for i := 0; i < 10; i++ {
|
||||
l.Errorln("error 1")
|
||||
l.Errorln("error 2")
|
||||
l.Warnln("warn 1")
|
||||
@@ -137,7 +137,7 @@ func TestReset(t *testing.T) {
|
||||
|
||||
l := loggers.New(opts)
|
||||
|
||||
for range 3 {
|
||||
for i := 0; i < 3; i++ {
|
||||
l.Errorln("error 1")
|
||||
l.Errorln("error 2")
|
||||
l.Errorln("error 1")
|
||||
|
||||
@@ -21,15 +21,7 @@ import (
|
||||
"github.com/bep/logg"
|
||||
)
|
||||
|
||||
// SetGlobalLogger sets the global logger.
|
||||
// This is used in a few places in Hugo, e.g. deprecated functions.
|
||||
func SetGlobalLogger(logger Logger) {
|
||||
logMu.Lock()
|
||||
defer logMu.Unlock()
|
||||
log = logger
|
||||
}
|
||||
|
||||
func initGlobalLogger(level logg.Level, panicOnWarnings bool) {
|
||||
func InitGlobalLogger(level logg.Level, panicOnWarnings bool) {
|
||||
logMu.Lock()
|
||||
defer logMu.Unlock()
|
||||
var logHookLast func(e *logg.Entry) error
|
||||
@@ -58,5 +50,5 @@ func Log() Logger {
|
||||
var log Logger
|
||||
|
||||
func init() {
|
||||
initGlobalLogger(logg.LevelWarn, false)
|
||||
InitGlobalLogger(logg.LevelWarn, false)
|
||||
}
|
||||
|
||||
@@ -73,14 +73,10 @@ func TestPrepareParams(t *testing.T) {
|
||||
for i, test := range tests {
|
||||
t.Run(fmt.Sprint(i), func(t *testing.T) {
|
||||
// PrepareParams modifies input.
|
||||
prepareClone := PrepareParamsClone(test.input)
|
||||
PrepareParams(test.input)
|
||||
if !reflect.DeepEqual(test.expected, test.input) {
|
||||
t.Errorf("[%d] Expected\n%#v, got\n%#v\n", i, test.expected, test.input)
|
||||
}
|
||||
if !reflect.DeepEqual(test.expected, prepareClone) {
|
||||
t.Errorf("[%d] Expected\n%#v, got\n%#v\n", i, test.expected, prepareClone)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ package maps
|
||||
|
||||
import (
|
||||
"github.com/gohugoio/hugo/common/hashing"
|
||||
"slices"
|
||||
)
|
||||
|
||||
// Ordered is a map that can be iterated in the order of insertion.
|
||||
@@ -65,7 +64,7 @@ func (m *Ordered[K, T]) Delete(key K) {
|
||||
delete(m.values, key)
|
||||
for i, k := range m.keys {
|
||||
if k == key {
|
||||
m.keys = slices.Delete(m.keys, i, i+1)
|
||||
m.keys = append(m.keys[:i], m.keys[i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
+1
-40
@@ -303,7 +303,7 @@ func toMergeStrategy(v any) ParamsMergeStrategy {
|
||||
}
|
||||
|
||||
// PrepareParams
|
||||
// * makes all the keys in the given map lower cased and will do so recursively.
|
||||
// * makes all the keys in the given map lower cased and will do so
|
||||
// * This will modify the map given.
|
||||
// * Any nested map[interface{}]interface{}, map[string]interface{},map[string]string will be converted to Params.
|
||||
// * Any _merge value will be converted to proper type and value.
|
||||
@@ -343,42 +343,3 @@ func PrepareParams(m Params) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PrepareParamsClone is like PrepareParams, but it does not modify the input.
|
||||
func PrepareParamsClone(m Params) Params {
|
||||
m2 := make(Params)
|
||||
for k, v := range m {
|
||||
var retyped bool
|
||||
lKey := strings.ToLower(k)
|
||||
if lKey == MergeStrategyKey {
|
||||
v = toMergeStrategy(v)
|
||||
retyped = true
|
||||
} else {
|
||||
switch vv := v.(type) {
|
||||
case map[any]any:
|
||||
var p Params = cast.ToStringMap(v)
|
||||
v = PrepareParamsClone(p)
|
||||
retyped = true
|
||||
case map[string]any:
|
||||
var p Params = v.(map[string]any)
|
||||
v = PrepareParamsClone(p)
|
||||
retyped = true
|
||||
case map[string]string:
|
||||
p := make(Params)
|
||||
for k, v := range vv {
|
||||
p[k] = v
|
||||
}
|
||||
v = p
|
||||
PrepareParams(p)
|
||||
retyped = true
|
||||
}
|
||||
}
|
||||
|
||||
if retyped || k != lKey {
|
||||
m2[lKey] = v
|
||||
} else {
|
||||
m2[k] = v
|
||||
}
|
||||
}
|
||||
return m2
|
||||
}
|
||||
|
||||
@@ -140,7 +140,7 @@ func TestScratchInParallel(t *testing.T) {
|
||||
for i := 1; i <= 10; i++ {
|
||||
wg.Add(1)
|
||||
go func(j int) {
|
||||
for k := range 10 {
|
||||
for k := 0; k < 10; k++ {
|
||||
newVal := int64(k + j)
|
||||
|
||||
_, err := scratch.Add(key, newVal)
|
||||
|
||||
@@ -42,7 +42,7 @@ func TestPara(t *testing.T) {
|
||||
c.Run("Order", func(c *qt.C) {
|
||||
n := 500
|
||||
ints := make([]int, n)
|
||||
for i := range n {
|
||||
for i := 0; i < n; i++ {
|
||||
ints[i] = i
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ func TestPara(t *testing.T) {
|
||||
|
||||
var result []int
|
||||
var mu sync.Mutex
|
||||
for i := range n {
|
||||
for i := 0; i < n; i++ {
|
||||
i := i
|
||||
r.Run(func() error {
|
||||
mu.Lock()
|
||||
@@ -78,7 +78,7 @@ func TestPara(t *testing.T) {
|
||||
|
||||
var counter int64
|
||||
|
||||
for range n {
|
||||
for i := 0; i < n; i++ {
|
||||
r.Run(func() error {
|
||||
atomic.AddInt64(&counter, 1)
|
||||
time.Sleep(1 * time.Millisecond)
|
||||
|
||||
@@ -165,7 +165,6 @@ func TestParse(t *testing.T) {
|
||||
c.Assert(p.Identifiers(), qt.DeepEquals, []string{"txt", "no"})
|
||||
c.Assert(p.Base(), qt.Equals, "/a/b.a.b.txt")
|
||||
c.Assert(p.BaseNoLeadingSlash(), qt.Equals, "a/b.a.b.txt")
|
||||
c.Assert(p.Path(), qt.Equals, "/a/b.a.b.no.txt")
|
||||
c.Assert(p.PathNoLang(), qt.Equals, "/a/b.a.b.txt")
|
||||
c.Assert(p.Ext(), qt.Equals, "txt")
|
||||
c.Assert(p.PathNoIdentifier(), qt.Equals, "/a/b.a.b")
|
||||
@@ -221,7 +220,6 @@ func TestParse(t *testing.T) {
|
||||
c.Assert(p.NameNoExt(), qt.Equals, "index.no")
|
||||
c.Assert(p.NameNoIdentifier(), qt.Equals, "index")
|
||||
c.Assert(p.NameNoLang(), qt.Equals, "index.md")
|
||||
c.Assert(p.Path(), qt.Equals, "/a/b/index.no.md")
|
||||
c.Assert(p.PathNoLang(), qt.Equals, "/a/b/index.md")
|
||||
c.Assert(p.Section(), qt.Equals, "a")
|
||||
},
|
||||
|
||||
@@ -51,7 +51,7 @@ func Run[T any](ctx context.Context, cfg Config[T]) Group[T] {
|
||||
// Buffered for performance.
|
||||
ch := make(chan T, cfg.NumWorkers)
|
||||
|
||||
for range cfg.NumWorkers {
|
||||
for i := 0; i < cfg.NumWorkers; i++ {
|
||||
g.Go(func() error {
|
||||
for {
|
||||
select {
|
||||
|
||||
@@ -103,7 +103,10 @@ func (r *RunEvery) Add(name string, f Func) {
|
||||
f.IntervalHigh = 20 * time.Second
|
||||
}
|
||||
|
||||
start := max(f.IntervalHigh/3, f.IntervalLow)
|
||||
start := f.IntervalHigh / 3
|
||||
if start < f.IntervalLow {
|
||||
start = f.IntervalLow
|
||||
}
|
||||
f.interval = start
|
||||
f.last = time.Now()
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ func ToStringSlicePreserveStringE(v any) ([]string, error) {
|
||||
switch vv.Kind() {
|
||||
case reflect.Slice, reflect.Array:
|
||||
result = make([]string, vv.Len())
|
||||
for i := range vv.Len() {
|
||||
for i := 0; i < vv.Len(); i++ {
|
||||
s, err := cast.ToStringE(vv.Index(i).Interface())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"slices"
|
||||
"sync"
|
||||
)
|
||||
|
||||
@@ -46,7 +45,7 @@ func (q *EvictingQueue[T]) Add(v T) *EvictingQueue[T] {
|
||||
if len(q.set) == q.size {
|
||||
// Full
|
||||
delete(q.set, q.vals[0])
|
||||
q.vals = slices.Delete(q.vals, 0, 1)
|
||||
q.vals = append(q.vals[:0], q.vals[1:]...)
|
||||
}
|
||||
q.set[v] = true
|
||||
q.vals = append(q.vals, v)
|
||||
|
||||
@@ -55,7 +55,7 @@ func TestEvictingStringQueueConcurrent(t *testing.T) {
|
||||
|
||||
queue := NewEvictingQueue[string](3)
|
||||
|
||||
for range 100 {
|
||||
for j := 0; j < 100; j++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
|
||||
@@ -59,7 +59,7 @@ func (k KeyValues) String() string {
|
||||
// KeyValues struct.
|
||||
func NewKeyValuesStrings(key string, values ...string) KeyValues {
|
||||
iv := make([]any, len(values))
|
||||
for i := range values {
|
||||
for i := 0; i < len(values); i++ {
|
||||
iv[i] = values[i]
|
||||
}
|
||||
return KeyValues{Key: key, Values: iv}
|
||||
|
||||
@@ -82,7 +82,7 @@ func init() {
|
||||
}
|
||||
configLanguageKeys = make(map[string]bool)
|
||||
addKeys := func(v reflect.Value) {
|
||||
for i := range v.NumField() {
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
name := strings.ToLower(v.Type().Field(i).Name)
|
||||
if skip[name] {
|
||||
continue
|
||||
@@ -128,9 +128,6 @@ type Config struct {
|
||||
// <docsmeta>{"identifiers": ["markup"] }</docsmeta>
|
||||
Markup markup_config.Config `mapstructure:"-"`
|
||||
|
||||
// ContentTypes are the media types that's considered content in Hugo.
|
||||
ContentTypes *config.ConfigNamespace[map[string]media.ContentTypeConfig, media.ContentTypes] `mapstructure:"-"`
|
||||
|
||||
// The mediatypes configuration section maps the MIME type (a string) to a configuration object for that type.
|
||||
// <docsmeta>{"identifiers": ["mediatypes"], "refs": ["types:media:type"] }</docsmeta>
|
||||
MediaTypes *config.ConfigNamespace[map[string]media.MediaTypeConfig, media.Types] `mapstructure:"-"`
|
||||
@@ -427,15 +424,6 @@ func (c *Config) CompileConfig(logger loggers.Logger) error {
|
||||
c.Services.X.DisableInlineCSS = c.Services.Twitter.DisableInlineCSS
|
||||
}
|
||||
|
||||
// Legacy permalink tokens
|
||||
vs := fmt.Sprintf("%v", c.Permalinks)
|
||||
if strings.Contains(vs, ":filename") {
|
||||
hugo.Deprecate("the \":filename\" permalink token", "Use \":contentbasename\" instead.", "0.144.0")
|
||||
}
|
||||
if strings.Contains(vs, ":slugorfilename") {
|
||||
hugo.Deprecate("the \":slugorfilename\" permalink token", "Use \":slugorcontentbasename\" instead.", "0.144.0")
|
||||
}
|
||||
|
||||
c.C = &ConfigCompiled{
|
||||
Timeout: timeout,
|
||||
BaseURL: baseURL,
|
||||
@@ -445,6 +433,7 @@ func (c *Config) CompileConfig(logger loggers.Logger) error {
|
||||
IgnoredLogs: ignoredLogIDs,
|
||||
KindOutputFormats: kindOutputFormats,
|
||||
DefaultOutputFormat: defaultOutputFormat,
|
||||
ContentTypes: media.DefaultContentTypes.FromTypes(c.MediaTypes.Config),
|
||||
CreateTitle: helpers.GetTitleFunc(c.TitleCaseStyle),
|
||||
IsUglyURLSection: isUglyURL,
|
||||
IgnoreFile: ignoreFile,
|
||||
@@ -482,6 +471,7 @@ type ConfigCompiled struct {
|
||||
ServerInterface string
|
||||
KindOutputFormats map[string]output.Formats
|
||||
DefaultOutputFormat output.Format
|
||||
ContentTypes media.ContentTypes
|
||||
DisabledKinds map[string]bool
|
||||
DisabledLanguages map[string]bool
|
||||
IgnoredLogs map[string]bool
|
||||
@@ -849,7 +839,7 @@ func (c *Configs) Init() error {
|
||||
c.Languages = languages
|
||||
c.LanguagesDefaultFirst = languagesDefaultFirst
|
||||
|
||||
c.ContentPathParser = &paths.PathParser{LanguageIndex: languagesDefaultFirst.AsIndexSet(), IsLangDisabled: c.Base.IsLangDisabled, IsContentExt: c.Base.ContentTypes.Config.IsContentSuffix}
|
||||
c.ContentPathParser = &paths.PathParser{LanguageIndex: languagesDefaultFirst.AsIndexSet(), IsLangDisabled: c.Base.IsLangDisabled, IsContentExt: c.Base.C.ContentTypes.IsContentSuffix}
|
||||
|
||||
c.configLangs = make([]config.AllProvider, len(c.Languages))
|
||||
for i, l := range c.LanguagesDefaultFirst {
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
qt "github.com/frankban/quicktest"
|
||||
"github.com/gohugoio/hugo/config/allconfig"
|
||||
"github.com/gohugoio/hugo/hugolib"
|
||||
"github.com/gohugoio/hugo/media"
|
||||
)
|
||||
|
||||
func TestDirsMount(t *testing.T) {
|
||||
@@ -98,7 +97,7 @@ suffixes = ["html", "xhtml"]
|
||||
b := hugolib.Test(t, files)
|
||||
|
||||
conf := b.H.Configs.Base
|
||||
contentTypes := conf.ContentTypes.Config
|
||||
contentTypes := conf.C.ContentTypes
|
||||
|
||||
b.Assert(contentTypes.HTML.Suffixes(), qt.DeepEquals, []string{"html", "xhtml"})
|
||||
b.Assert(contentTypes.Markdown.Suffixes(), qt.DeepEquals, []string{"md", "mdown", "markdown"})
|
||||
@@ -216,21 +215,3 @@ weight = 3
|
||||
b := hugolib.Test(t, files)
|
||||
b.Assert(b.H.Configs.LanguageConfigSlice[0].Title, qt.Equals, `TITLE_DE`)
|
||||
}
|
||||
|
||||
func TestContentTypesDefault(t *testing.T) {
|
||||
files := `
|
||||
-- hugo.toml --
|
||||
baseURL = "https://example.com"
|
||||
|
||||
|
||||
`
|
||||
|
||||
b := hugolib.Test(t, files)
|
||||
|
||||
ct := b.H.Configs.Base.ContentTypes
|
||||
c := ct.Config
|
||||
s := ct.SourceStructure.(map[string]media.ContentTypeConfig)
|
||||
|
||||
b.Assert(c.IsContentFile("foo.md"), qt.Equals, true)
|
||||
b.Assert(len(s), qt.Equals, 6)
|
||||
}
|
||||
|
||||
@@ -163,15 +163,6 @@ var allDecoderSetups = map[string]decodeWeight{
|
||||
return err
|
||||
},
|
||||
},
|
||||
"contenttypes": {
|
||||
key: "contenttypes",
|
||||
weight: 100, // This needs to be decoded after media types.
|
||||
decode: func(d decodeWeight, p decodeConfig) error {
|
||||
var err error
|
||||
p.c.ContentTypes, err = media.DecodeContentTypes(p.p.GetStringMap(d.key), p.c.MediaTypes.Config)
|
||||
return err
|
||||
},
|
||||
},
|
||||
"mediatypes": {
|
||||
key: "mediatypes",
|
||||
decode: func(d decodeWeight, p decodeConfig) error {
|
||||
|
||||
@@ -145,7 +145,7 @@ func (c ConfigLanguage) NewIdentityManager(name string, opts ...identity.Manager
|
||||
}
|
||||
|
||||
func (c ConfigLanguage) ContentTypes() config.ContentTypesProvider {
|
||||
return c.config.ContentTypes.Config
|
||||
return c.config.C.ContentTypes
|
||||
}
|
||||
|
||||
// GetConfigSection is mostly used in tests. The switch statement isn't complete, but what's in use.
|
||||
|
||||
@@ -91,7 +91,7 @@ func LoadConfig(d ConfigSourceDescriptor) (*Configs, error) {
|
||||
return nil, fmt.Errorf("failed to init config: %w", err)
|
||||
}
|
||||
|
||||
loggers.SetGlobalLogger(d.Logger)
|
||||
loggers.InitGlobalLogger(d.Logger.Level(), configs.Base.PanicOnWarning)
|
||||
|
||||
return configs, nil
|
||||
}
|
||||
@@ -305,7 +305,7 @@ func (l configLoader) applyOsEnvOverrides(environ []string) error {
|
||||
_, ok := allDecoderSetups[key]
|
||||
if ok {
|
||||
// A map.
|
||||
if v, err := metadecoders.Default.UnmarshalStringTo(env.Value, map[string]any{}); err == nil {
|
||||
if v, err := metadecoders.Default.UnmarshalStringTo(env.Value, map[string]interface{}{}); err == nil {
|
||||
val = v
|
||||
}
|
||||
}
|
||||
|
||||
+24
-96
@@ -15,7 +15,6 @@ package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
@@ -28,7 +27,6 @@ import (
|
||||
"github.com/gohugoio/hugo/common/herrors"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"github.com/spf13/cast"
|
||||
"slices"
|
||||
)
|
||||
|
||||
type BaseConfig struct {
|
||||
@@ -129,7 +127,7 @@ func (w BuildStats) Enabled() bool {
|
||||
}
|
||||
|
||||
func (b BuildConfig) clone() BuildConfig {
|
||||
b.CacheBusters = slices.Clone(b.CacheBusters)
|
||||
b.CacheBusters = append([]CacheBuster{}, b.CacheBusters...)
|
||||
return b
|
||||
}
|
||||
|
||||
@@ -228,22 +226,7 @@ type Server struct {
|
||||
Redirects []Redirect
|
||||
|
||||
compiledHeaders []glob.Glob
|
||||
compiledRedirects []redirect
|
||||
}
|
||||
|
||||
type redirect struct {
|
||||
from glob.Glob
|
||||
fromRe *regexp.Regexp
|
||||
headers map[string]glob.Glob
|
||||
}
|
||||
|
||||
func (r redirect) matchHeader(header http.Header) bool {
|
||||
for k, v := range r.headers {
|
||||
if !v.Match(header.Get(k)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
compiledRedirects []glob.Glob
|
||||
}
|
||||
|
||||
func (s *Server) CompileConfig(logger loggers.Logger) error {
|
||||
@@ -251,41 +234,10 @@ func (s *Server) CompileConfig(logger loggers.Logger) error {
|
||||
return nil
|
||||
}
|
||||
for _, h := range s.Headers {
|
||||
g, err := glob.Compile(h.For)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to compile Headers glob %q: %w", h.For, err)
|
||||
}
|
||||
s.compiledHeaders = append(s.compiledHeaders, g)
|
||||
s.compiledHeaders = append(s.compiledHeaders, glob.MustCompile(h.For))
|
||||
}
|
||||
for _, r := range s.Redirects {
|
||||
if r.From == "" && r.FromRe == "" {
|
||||
return fmt.Errorf("redirects must have either From or FromRe set")
|
||||
}
|
||||
rd := redirect{
|
||||
headers: make(map[string]glob.Glob),
|
||||
}
|
||||
if r.From != "" {
|
||||
g, err := glob.Compile(r.From)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to compile Redirect glob %q: %w", r.From, err)
|
||||
}
|
||||
rd.from = g
|
||||
}
|
||||
if r.FromRe != "" {
|
||||
re, err := regexp.Compile(r.FromRe)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to compile Redirect regexp %q: %w", r.FromRe, err)
|
||||
}
|
||||
rd.fromRe = re
|
||||
}
|
||||
for k, v := range r.FromHeaders {
|
||||
g, err := glob.Compile(v)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to compile Redirect header glob %q: %w", v, err)
|
||||
}
|
||||
rd.headers[k] = g
|
||||
}
|
||||
s.compiledRedirects = append(s.compiledRedirects, rd)
|
||||
s.compiledRedirects = append(s.compiledRedirects, glob.MustCompile(r.From))
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -314,42 +266,22 @@ func (s *Server) MatchHeaders(pattern string) []types.KeyValueStr {
|
||||
return matches
|
||||
}
|
||||
|
||||
func (s *Server) MatchRedirect(pattern string, header http.Header) Redirect {
|
||||
func (s *Server) MatchRedirect(pattern string) Redirect {
|
||||
if s.compiledRedirects == nil {
|
||||
return Redirect{}
|
||||
}
|
||||
|
||||
pattern = strings.TrimSuffix(pattern, "index.html")
|
||||
|
||||
for i, r := range s.compiledRedirects {
|
||||
for i, g := range s.compiledRedirects {
|
||||
redir := s.Redirects[i]
|
||||
|
||||
var found bool
|
||||
|
||||
if r.from != nil {
|
||||
if r.from.Match(pattern) {
|
||||
found = header == nil || r.matchHeader(header)
|
||||
// We need to do regexp group replacements if needed.
|
||||
}
|
||||
// No redirect to self.
|
||||
if redir.To == pattern {
|
||||
return Redirect{}
|
||||
}
|
||||
|
||||
if r.fromRe != nil {
|
||||
m := r.fromRe.FindStringSubmatch(pattern)
|
||||
if m != nil {
|
||||
if !found {
|
||||
found = header == nil || r.matchHeader(header)
|
||||
}
|
||||
|
||||
if found {
|
||||
// Replace $1, $2 etc. in To.
|
||||
for i, g := range m[1:] {
|
||||
redir.To = strings.ReplaceAll(redir.To, fmt.Sprintf("$%d", i+1), g)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if found {
|
||||
if g.Match(pattern) {
|
||||
return redir
|
||||
}
|
||||
}
|
||||
@@ -363,22 +295,8 @@ type Headers struct {
|
||||
}
|
||||
|
||||
type Redirect struct {
|
||||
// From is the Glob pattern to match.
|
||||
// One of From or FromRe must be set.
|
||||
From string
|
||||
|
||||
// FromRe is the regexp to match.
|
||||
// This regexp can contain group matches (e.g. $1) that can be used in the To field.
|
||||
// One of From or FromRe must be set.
|
||||
FromRe string
|
||||
|
||||
// To is the target URL.
|
||||
To string
|
||||
|
||||
// Headers to match for the redirect.
|
||||
// This maps the HTTP header name to a Glob pattern with values to match.
|
||||
// If the map is empty, the redirect will always be triggered.
|
||||
FromHeaders map[string]string
|
||||
To string
|
||||
|
||||
// HTTP status code to use for the redirect.
|
||||
// A status code of 200 will trigger a URL rewrite.
|
||||
@@ -451,7 +369,7 @@ func (c *CacheBuster) CompileConfig(logger loggers.Logger) error {
|
||||
}
|
||||
|
||||
func (r Redirect) IsZero() bool {
|
||||
return r.From == "" && r.FromRe == ""
|
||||
return r.From == ""
|
||||
}
|
||||
|
||||
const (
|
||||
@@ -465,7 +383,17 @@ func DecodeServer(cfg Provider) (Server, error) {
|
||||
_ = mapstructure.WeakDecode(cfg.GetStringMap("server"), s)
|
||||
|
||||
for i, redir := range s.Redirects {
|
||||
redir.To = strings.TrimSuffix(redir.To, "index.html")
|
||||
// Get it in line with the Hugo server for OK responses.
|
||||
// We currently treat the 404 as a special case, they are always "ugly", so keep them as is.
|
||||
if redir.Status != 404 {
|
||||
redir.To = strings.TrimSuffix(redir.To, "index.html")
|
||||
if !strings.HasPrefix(redir.To, "https") && !strings.HasSuffix(redir.To, "/") {
|
||||
// There are some tricky infinite loop situations when dealing
|
||||
// when the target does not have a trailing slash.
|
||||
// This can certainly be handled better, but not time for that now.
|
||||
return Server{}, fmt.Errorf("unsupported redirect to value %q in server config; currently this must be either a remote destination or a local folder, e.g. \"/blog/\" or \"/blog/index.html\"", redir.To)
|
||||
}
|
||||
}
|
||||
s.Redirects[i] = redir
|
||||
}
|
||||
|
||||
@@ -473,7 +401,7 @@ func DecodeServer(cfg Provider) (Server, error) {
|
||||
// Set up a default redirect for 404s.
|
||||
s.Redirects = []Redirect{
|
||||
{
|
||||
From: "/**",
|
||||
From: "**",
|
||||
To: "/404.html",
|
||||
Status: 404,
|
||||
},
|
||||
|
||||
+36
-42
@@ -71,28 +71,7 @@ X-Content-Type-Options = "nosniff"
|
||||
|
||||
[[server.redirects]]
|
||||
from = "/foo/**"
|
||||
to = "/baz/index.html"
|
||||
status = 200
|
||||
|
||||
[[server.redirects]]
|
||||
from = "/loop/**"
|
||||
to = "/loop/foo/"
|
||||
status = 200
|
||||
|
||||
[[server.redirects]]
|
||||
from = "/b/**"
|
||||
fromRe = "/b/(.*)/"
|
||||
to = "/baz/$1/"
|
||||
status = 200
|
||||
|
||||
[[server.redirects]]
|
||||
fromRe = "/c/(.*)/"
|
||||
to = "/boo/$1/"
|
||||
status = 200
|
||||
|
||||
[[server.redirects]]
|
||||
fromRe = "/d/(.*)/"
|
||||
to = "/boo/$1/"
|
||||
to = "/foo/index.html"
|
||||
status = 200
|
||||
|
||||
[[server.redirects]]
|
||||
@@ -100,6 +79,11 @@ from = "/google/**"
|
||||
to = "https://google.com/"
|
||||
status = 301
|
||||
|
||||
[[server.redirects]]
|
||||
from = "/**"
|
||||
to = "/default/index.html"
|
||||
status = 301
|
||||
|
||||
|
||||
|
||||
`, "toml")
|
||||
@@ -116,35 +100,45 @@ status = 301
|
||||
{Key: "X-XSS-Protection", Value: "1; mode=block"},
|
||||
})
|
||||
|
||||
c.Assert(s.MatchRedirect("/foo/bar/baz", nil), qt.DeepEquals, Redirect{
|
||||
c.Assert(s.MatchRedirect("/foo/bar/baz"), qt.DeepEquals, Redirect{
|
||||
From: "/foo/**",
|
||||
To: "/baz/",
|
||||
To: "/foo/",
|
||||
Status: 200,
|
||||
})
|
||||
|
||||
c.Assert(s.MatchRedirect("/foo/bar/", nil), qt.DeepEquals, Redirect{
|
||||
From: "/foo/**",
|
||||
To: "/baz/",
|
||||
Status: 200,
|
||||
c.Assert(s.MatchRedirect("/someother"), qt.DeepEquals, Redirect{
|
||||
From: "/**",
|
||||
To: "/default/",
|
||||
Status: 301,
|
||||
})
|
||||
|
||||
c.Assert(s.MatchRedirect("/b/c/", nil), qt.DeepEquals, Redirect{
|
||||
From: "/b/**",
|
||||
FromRe: "/b/(.*)/",
|
||||
To: "/baz/c/",
|
||||
Status: 200,
|
||||
})
|
||||
|
||||
c.Assert(s.MatchRedirect("/c/d/", nil).To, qt.Equals, "/boo/d/")
|
||||
c.Assert(s.MatchRedirect("/c/d/e/", nil).To, qt.Equals, "/boo/d/e/")
|
||||
|
||||
c.Assert(s.MatchRedirect("/someother", nil), qt.DeepEquals, Redirect{})
|
||||
|
||||
c.Assert(s.MatchRedirect("/google/foo", nil), qt.DeepEquals, Redirect{
|
||||
c.Assert(s.MatchRedirect("/google/foo"), qt.DeepEquals, Redirect{
|
||||
From: "/google/**",
|
||||
To: "https://google.com/",
|
||||
Status: 301,
|
||||
})
|
||||
|
||||
// No redirect loop, please.
|
||||
c.Assert(s.MatchRedirect("/default/index.html"), qt.DeepEquals, Redirect{})
|
||||
c.Assert(s.MatchRedirect("/default/"), qt.DeepEquals, Redirect{})
|
||||
|
||||
for _, errorCase := range []string{
|
||||
`[[server.redirects]]
|
||||
from = "/**"
|
||||
to = "/file"
|
||||
status = 301`,
|
||||
`[[server.redirects]]
|
||||
from = "/**"
|
||||
to = "/foo/file.html"
|
||||
status = 301`,
|
||||
} {
|
||||
|
||||
cfg, err := FromConfigString(errorCase, "toml")
|
||||
c.Assert(err, qt.IsNil)
|
||||
_, err = DecodeServer(cfg)
|
||||
c.Assert(err, qt.Not(qt.IsNil))
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildConfigCacheBusters(t *testing.T) {
|
||||
@@ -166,7 +160,7 @@ func TestBuildConfigCacheBusters(t *testing.T) {
|
||||
func TestBuildConfigCacheBusterstTailwindSetup(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
cfg := New()
|
||||
cfg.Set("build", map[string]any{
|
||||
cfg.Set("build", map[string]interface{}{
|
||||
"cacheBusters": []map[string]string{
|
||||
{
|
||||
"source": "assets/watching/hugo_stats\\.json",
|
||||
|
||||
@@ -15,6 +15,7 @@ package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
@@ -25,6 +26,42 @@ import (
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
// ConfigRootKeysSet contains all of the config map root keys.
|
||||
ConfigRootKeysSet = map[string]bool{
|
||||
"build": true,
|
||||
"caches": true,
|
||||
"cascade": true,
|
||||
"frontmatter": true,
|
||||
"languages": true,
|
||||
"imaging": true,
|
||||
"markup": true,
|
||||
"mediatypes": true,
|
||||
"menus": true,
|
||||
"minify": true,
|
||||
"module": true,
|
||||
"outputformats": true,
|
||||
"params": true,
|
||||
"permalinks": true,
|
||||
"related": true,
|
||||
"sitemap": true,
|
||||
"privacy": true,
|
||||
"security": true,
|
||||
"taxonomies": true,
|
||||
}
|
||||
|
||||
// ConfigRootKeys is a sorted version of ConfigRootKeysSet.
|
||||
ConfigRootKeys []string
|
||||
)
|
||||
|
||||
func init() {
|
||||
for k := range ConfigRootKeysSet {
|
||||
ConfigRootKeys = append(ConfigRootKeys, k)
|
||||
}
|
||||
sort.Strings(ConfigRootKeys)
|
||||
}
|
||||
|
||||
// New creates a Provider backed by an empty maps.Params.
|
||||
func New() Provider {
|
||||
return &defaultConfigProvider{
|
||||
@@ -345,7 +382,7 @@ func (c *defaultConfigProvider) getNestedKeyAndMap(key string, create bool) (str
|
||||
c.keyCache.Store(key, parts)
|
||||
}
|
||||
current := c.root
|
||||
for i := range len(parts) - 1 {
|
||||
for i := 0; i < len(parts)-1; i++ {
|
||||
next, found := current[parts[i]]
|
||||
if !found {
|
||||
if create {
|
||||
|
||||
@@ -332,7 +332,7 @@ func TestDefaultConfigProvider(t *testing.T) {
|
||||
return nil
|
||||
}
|
||||
|
||||
for i := range 20 {
|
||||
for i := 0; i < 20; i++ {
|
||||
i := i
|
||||
r.Run(func() error {
|
||||
const v = 42
|
||||
|
||||
@@ -29,7 +29,7 @@ func TestNamespace(t *testing.T) {
|
||||
// ns, err := config.DecodeNamespace[map[string]DocsMediaTypeConfig](in, defaultMediaTypesConfig, buildConfig)
|
||||
|
||||
ns, err := DecodeNamespace[[]*tstNsExt](
|
||||
map[string]any{"foo": "bar"},
|
||||
map[string]interface{}{"foo": "bar"},
|
||||
func(v any) (*tstNsExt, any, error) {
|
||||
t := &tstNsExt{}
|
||||
m, err := maps.ToStringMapE(v)
|
||||
@@ -42,7 +42,7 @@ func TestNamespace(t *testing.T) {
|
||||
|
||||
c.Assert(err, qt.IsNil)
|
||||
c.Assert(ns, qt.Not(qt.IsNil))
|
||||
c.Assert(ns.SourceStructure, qt.DeepEquals, map[string]any{"foo": "bar"})
|
||||
c.Assert(ns.SourceStructure, qt.DeepEquals, map[string]interface{}{"foo": "bar"})
|
||||
c.Assert(ns.SourceHash, qt.Equals, "1420f6c7782f7459")
|
||||
c.Assert(ns.Config, qt.DeepEquals, &tstNsExt{Foo: "bar"})
|
||||
c.Assert(ns.Signature(), qt.DeepEquals, []*tstNsExt(nil))
|
||||
|
||||
@@ -36,6 +36,10 @@ respectDoNotTrack = true
|
||||
[privacy.instagram]
|
||||
disable = true
|
||||
simple = true
|
||||
[privacy.twitter]
|
||||
disable = true
|
||||
enableDNT = true
|
||||
simple = true
|
||||
[privacy.x]
|
||||
disable = true
|
||||
enableDNT = true
|
||||
@@ -59,8 +63,8 @@ simple = true
|
||||
got := []bool{
|
||||
pc.Disqus.Disable, pc.GoogleAnalytics.Disable,
|
||||
pc.GoogleAnalytics.RespectDoNotTrack, pc.Instagram.Disable,
|
||||
pc.Instagram.Simple,
|
||||
pc.Vimeo.Disable, pc.Vimeo.EnableDNT, pc.Vimeo.Simple,
|
||||
pc.Instagram.Simple, pc.Twitter.Disable, pc.Twitter.EnableDNT,
|
||||
pc.Twitter.Simple, pc.Vimeo.Disable, pc.Vimeo.EnableDNT, pc.Vimeo.Simple,
|
||||
pc.YouTube.PrivacyEnhanced, pc.YouTube.Disable, pc.X.Disable, pc.X.EnableDNT,
|
||||
pc.X.Simple,
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ func NewWhitelist(patterns ...string) (Whitelist, error) {
|
||||
|
||||
var patternsr []*regexp.Regexp
|
||||
|
||||
for i := range patterns {
|
||||
for i := 0; i < len(patterns); i++ {
|
||||
p := strings.TrimSpace(patterns[i])
|
||||
if p == "" {
|
||||
continue
|
||||
|
||||
@@ -129,7 +129,7 @@ site RegularPages: {{ len site.RegularPages }}
|
||||
|
||||
`
|
||||
|
||||
c.Assert(afero.WriteFile(mm, filepath.Join(archetypeDir, "index.md"), fmt.Appendf(nil, contentFile, "index.md"), 0o755), qt.IsNil)
|
||||
c.Assert(afero.WriteFile(mm, filepath.Join(archetypeDir, "index.md"), []byte(fmt.Sprintf(contentFile, "index.md")), 0o755), qt.IsNil)
|
||||
c.Assert(afero.WriteFile(mm, filepath.Join(defaultArchetypeDir, "index.md"), []byte("default archetype index.md"), 0o755), qt.IsNil)
|
||||
|
||||
c.Assert(initFs(mm), qt.IsNil)
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
//go:build withdeploy
|
||||
// +build withdeploy
|
||||
|
||||
package deploy
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
//go:build withdeploy
|
||||
// +build withdeploy
|
||||
|
||||
package deploy
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
//go:build !solaris && withdeploy
|
||||
// +build !solaris,withdeploy
|
||||
|
||||
package deploy
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
//go:build withdeploy
|
||||
// +build withdeploy
|
||||
|
||||
package deploy
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
//go:build withdeploy
|
||||
// +build withdeploy
|
||||
|
||||
package deployconfig
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
//go:build withdeploy
|
||||
// +build withdeploy
|
||||
|
||||
package deploy
|
||||
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
# Config file for codespell.
|
||||
# https://github.com/codespell-project/codespell#using-a-config-file
|
||||
|
||||
[codespell]
|
||||
|
||||
# Comma separated list of dirs to be skipped.
|
||||
skip = _vendor,.cspell.json,chroma.css,chroma_dark.css
|
||||
|
||||
# Comma separated list of words to be ignored. Words must be lowercased.
|
||||
ignore-words-list = abl,edn,te,ue,trys,januar,womens,crossreferences
|
||||
|
||||
# Check file names as well.
|
||||
check-filenames = true
|
||||
@@ -68,7 +68,6 @@
|
||||
"# ----------------------------------------------------------------------",
|
||||
"# cspell: ignore hugo terminology",
|
||||
"# ----------------------------------------------------------------------",
|
||||
"alignx",
|
||||
"attrlink",
|
||||
"canonify",
|
||||
"codeowners",
|
||||
@@ -86,7 +85,6 @@
|
||||
"stringifier",
|
||||
"struct",
|
||||
"toclevels",
|
||||
"unmarshal",
|
||||
"unpublishdate",
|
||||
"zgotmplz",
|
||||
"# ----------------------------------------------------------------------",
|
||||
@@ -160,8 +158,6 @@
|
||||
"# cspell: ignore miscellaneous",
|
||||
"# ----------------------------------------------------------------------",
|
||||
"achristie",
|
||||
"ccpa",
|
||||
"crpa",
|
||||
"ddmaurier",
|
||||
"dring",
|
||||
"fleqn",
|
||||
@@ -175,7 +171,6 @@
|
||||
"rsmith",
|
||||
"tdewolff",
|
||||
"tjones",
|
||||
"vcard",
|
||||
"wcag",
|
||||
"xfeff"
|
||||
]
|
||||
|
||||
-1
@@ -1 +0,0 @@
|
||||
blank_issues_enabled: false
|
||||
-6
@@ -1,6 +0,0 @@
|
||||
---
|
||||
name: Default
|
||||
about: This is the default issue template.
|
||||
labels:
|
||||
- NeedsTriage
|
||||
---
|
||||
-5
@@ -20,8 +20,3 @@ jobs:
|
||||
incremental_files_only: true
|
||||
inline: warning
|
||||
strict: false
|
||||
- uses: codespell-project/actions-codespell@v2
|
||||
with:
|
||||
check_filenames: true
|
||||
check_hidden: true
|
||||
# by default, codespell uses configuration from the .codespellrc
|
||||
|
||||
+6
-9
@@ -1,13 +1,10 @@
|
||||
.DS_Store
|
||||
.hugo_build.lock
|
||||
/.idea
|
||||
/.vscode
|
||||
/dist
|
||||
/public
|
||||
hugo_stats.json
|
||||
node_modules/
|
||||
/dist
|
||||
node_modules
|
||||
nohup.out
|
||||
package-lock.json
|
||||
public/
|
||||
resources/
|
||||
trace.out
|
||||
.DS_Store
|
||||
trace.out
|
||||
.hugo_build.lock
|
||||
resources/_gen/images/
|
||||
+200
-2
@@ -1,3 +1,201 @@
|
||||
See [content/LICENSE.md](content/LICENSE.md) for the license of the content of this repository.
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
The theme (layouts, CSS, JavaScript etc.) of this repository has no open source license. It is custom made for the Hugo sites and is not meant for reuse.
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
@@ -16,12 +16,3 @@ Please see the [contributing] section for guidelines, examples, and process.
|
||||
[friends]: https://github.com/gohugoio/hugo/graphs/contributors
|
||||
[go]: https://go.dev/
|
||||
[contributing]: https://gohugo.io/contribute/documentation
|
||||
|
||||
# Install
|
||||
|
||||
```bash
|
||||
npm i
|
||||
hugo server
|
||||
```
|
||||
|
||||
**Note:** We're working on removing the need to run `npm i` for local development. Stay tuned.
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,21 @@
|
||||
.animated {
|
||||
animation-duration: .5s;
|
||||
animation-fill-mode: forwards;
|
||||
animation-timing-function: ease-in-out;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
.fadeIn {
|
||||
animation-name: fadeIn;
|
||||
}
|
||||
.animated-delay-1 {
|
||||
animation-delay: 0.5s;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/* These styles enhance the home page carousel, located here: themes/gohugoioTheme/layouts/partials/home-page-sections/showcase.html */
|
||||
.overflow-x-scroll{
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
.row {
|
||||
transition: 450ms transform;
|
||||
font-size: 0;
|
||||
}
|
||||
.tile {
|
||||
transition: 450ms all;
|
||||
}
|
||||
.details {
|
||||
background: -webkit-gradient(linear, left bottom, left top, from(rgba(0,0,0,0.9)), to(rgba(0,0,0,0)));
|
||||
background: linear-gradient(to top, rgba(0,0,0,0.9) 0%, rgba(0,0,0,0) 100%);
|
||||
transition: 450ms opacity;
|
||||
}
|
||||
.tile:hover .details {
|
||||
opacity: 1;
|
||||
}
|
||||
.row:hover .tile {
|
||||
opacity: 0.3;
|
||||
}
|
||||
.row:hover .tile:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
+5
-25
@@ -1,14 +1,10 @@
|
||||
/* Background */ .bg { background-color: var(--color-light); }
|
||||
/* PreWrapper */ .chroma { background-color: var(--color-light); }
|
||||
/* Other */ .chroma .x { }
|
||||
/* Background */ .chroma { background-color: #ffffff }
|
||||
/* Error */ .chroma .err { color: #a61717; background-color: #e3d2d2 }
|
||||
/* CodeLine */ .chroma .cl { }
|
||||
/* LineTableTD */ .chroma .lntd { vertical-align: top; padding: 0; margin: 0; border: 0; }
|
||||
/* LineTable */ .chroma .lntable { border-spacing: 0; padding: 0; margin: 0; border: 0; }
|
||||
/* LineHighlight */ .chroma .hl { background-color: #ffffcc }
|
||||
/* LineNumbersTable */ .chroma .lnt { white-space: pre; user-select: none; margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f }
|
||||
/* LineNumbers */ .chroma .ln { white-space: pre; user-select: none; margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f }
|
||||
/* Line */ .chroma .line { display: flex; }
|
||||
/* LineTable */ .chroma .lntable { border-spacing: 0; padding: 0; margin: 0; border: 0; width: auto; overflow: auto; display: block; }
|
||||
/* LineHighlight */ .chroma .hl { display: block; width: 100%;background-color: #ffffcc }
|
||||
/* LineNumbersTable */ .chroma .lnt { margin-right: 0.4em; padding: 0 0.4em 0 0.4em; }
|
||||
/* LineNumbers */ .chroma .ln { margin-right: 0.4em; padding: 0 0.4em 0 0.4em; }
|
||||
/* Keyword */ .chroma .k { font-weight: bold }
|
||||
/* KeywordConstant */ .chroma .kc { font-weight: bold }
|
||||
/* KeywordDeclaration */ .chroma .kd { font-weight: bold }
|
||||
@@ -16,29 +12,16 @@
|
||||
/* KeywordPseudo */ .chroma .kp { font-weight: bold }
|
||||
/* KeywordReserved */ .chroma .kr { font-weight: bold }
|
||||
/* KeywordType */ .chroma .kt { color: #445588; font-weight: bold }
|
||||
/* Name */ .chroma .n { }
|
||||
/* NameAttribute */ .chroma .na { color: #008080 }
|
||||
/* NameBuiltin */ .chroma .nb { color: #999999 }
|
||||
/* NameBuiltinPseudo */ .chroma .bp { }
|
||||
/* NameClass */ .chroma .nc { color: #445588; font-weight: bold }
|
||||
/* NameConstant */ .chroma .no { color: #008080 }
|
||||
/* NameDecorator */ .chroma .nd { }
|
||||
/* NameEntity */ .chroma .ni { color: #800080 }
|
||||
/* NameException */ .chroma .ne { color: #990000; font-weight: bold }
|
||||
/* NameFunction */ .chroma .nf { color: #990000; font-weight: bold }
|
||||
/* NameFunctionMagic */ .chroma .fm { }
|
||||
/* NameLabel */ .chroma .nl { }
|
||||
/* NameNamespace */ .chroma .nn { color: #555555 }
|
||||
/* NameOther */ .chroma .nx { }
|
||||
/* NameProperty */ .chroma .py { }
|
||||
/* NameTag */ .chroma .nt { color: #000080 }
|
||||
/* NameVariable */ .chroma .nv { color: #008080 }
|
||||
/* NameVariableClass */ .chroma .vc { }
|
||||
/* NameVariableGlobal */ .chroma .vg { }
|
||||
/* NameVariableInstance */ .chroma .vi { }
|
||||
/* NameVariableMagic */ .chroma .vm { }
|
||||
/* Literal */ .chroma .l { }
|
||||
/* LiteralDate */ .chroma .ld { }
|
||||
/* LiteralString */ .chroma .s { color: #bb8844 }
|
||||
/* LiteralStringAffix */ .chroma .sa { color: #bb8844 }
|
||||
/* LiteralStringBacktick */ .chroma .sb { color: #bb8844 }
|
||||
@@ -62,7 +45,6 @@
|
||||
/* LiteralNumberOct */ .chroma .mo { color: #009999 }
|
||||
/* Operator */ .chroma .o { font-weight: bold }
|
||||
/* OperatorWord */ .chroma .ow { font-weight: bold }
|
||||
/* Punctuation */ .chroma .p { }
|
||||
/* Comment */ .chroma .c { color: #999988; font-style: italic }
|
||||
/* CommentHashbang */ .chroma .ch { color: #999988; font-style: italic }
|
||||
/* CommentMultiline */ .chroma .cm { color: #999988; font-style: italic }
|
||||
@@ -70,7 +52,6 @@
|
||||
/* CommentSpecial */ .chroma .cs { color: #999999; font-weight: bold; font-style: italic }
|
||||
/* CommentPreproc */ .chroma .cp { color: #999999; font-weight: bold }
|
||||
/* CommentPreprocFile */ .chroma .cpf { color: #999999; font-weight: bold }
|
||||
/* Generic */ .chroma .g { }
|
||||
/* GenericDeleted */ .chroma .gd { color: #000000; background-color: #ffdddd }
|
||||
/* GenericEmph */ .chroma .ge { font-style: italic }
|
||||
/* GenericError */ .chroma .gr { color: #aa0000 }
|
||||
@@ -81,5 +62,4 @@
|
||||
/* GenericStrong */ .chroma .gs { font-weight: bold }
|
||||
/* GenericSubheading */ .chroma .gu { color: #aaaaaa }
|
||||
/* GenericTraceback */ .chroma .gt { color: #aa0000 }
|
||||
/* GenericUnderline */ .chroma .gl { text-decoration: underline }
|
||||
/* TextWhitespace */ .chroma .w { color: #bbbbbb }
|
||||
@@ -0,0 +1,89 @@
|
||||
.chroma .lntable pre {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.chroma .lntable pre code {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
code {
|
||||
padding: 2px 3px;
|
||||
margin: 0;
|
||||
font-size: 93.75%;
|
||||
background-color: rgba(27,31,35,0.05);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
pre code {
|
||||
display: block;
|
||||
padding: 1.5em 1.5em;
|
||||
font-size: .875rem;
|
||||
line-height: 2;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
pre {
|
||||
background-color: #fff;
|
||||
color: #333;
|
||||
white-space: pre;
|
||||
hyphens: none;
|
||||
position: relative;
|
||||
border-width: 1px;
|
||||
border-color: #ccc;
|
||||
border-style: solid;
|
||||
}
|
||||
|
||||
/* The Pygments highlighter comes with its own styles. */
|
||||
.highlight pre {
|
||||
background-color: inherit;
|
||||
color: inherit;
|
||||
padding: 0.5em;
|
||||
font-size: .875rem;
|
||||
}
|
||||
|
||||
|
||||
/*We are adding the copy button content here so we can change it with javascript. See the "Clipboard scripts"*/
|
||||
.copy:after {
|
||||
content: "Copy"
|
||||
}
|
||||
.copied:after {
|
||||
content: "Copied"
|
||||
}
|
||||
|
||||
@media (--breakpoint-large) {
|
||||
.full-width
|
||||
{
|
||||
/*width: 100vw;
|
||||
position: relative;
|
||||
left: 50%;
|
||||
right: 50%;
|
||||
margin-left: -50vw;
|
||||
margin-right: -50vw;*/
|
||||
/*width: 60vw;*/
|
||||
/*position: relative;
|
||||
left: 50%;
|
||||
right: 50%;*/
|
||||
/*margin-left: -30vw;*/
|
||||
margin-right: -30vw;
|
||||
max-width: 100vw;
|
||||
}
|
||||
}
|
||||
|
||||
.code-block .line-numbers-rows {
|
||||
background: #2f3a46;
|
||||
border: none;
|
||||
bottom: -50px;
|
||||
color: #98a4b3;
|
||||
left: -178px;
|
||||
padding: 50px 0;
|
||||
top: -50px;
|
||||
width: 138px
|
||||
}
|
||||
|
||||
.code-block .line-numbers-rows>span:before {
|
||||
color: inherit;
|
||||
padding-right: 30px
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
.primary-color {color: var(--primary-color)}
|
||||
.bg-primary-color {background-color: var(--primary-color)}
|
||||
.hover-bg-primary-color:hover {background-color: var(--primary-color)}
|
||||
|
||||
.primary-color-dark {color: var(--primary-color-dark)}
|
||||
.bg-primary-color-dark {background-color: var(--primary-color-dark)}
|
||||
.hover-bg-primary-color-dark:hover {background-color: var(--primary-color-dark)}
|
||||
|
||||
.primary-color-light {color: var(--primary-color-light)}
|
||||
.bg-primary-color-light {background-color: var(--primary-color-light)}
|
||||
.hover-bg-primary-color-light:hover {background-color: var(--primary-color-light)}
|
||||
|
||||
.accent-color {color: var(--accent-color)}
|
||||
.bg-accent-color {background-color: var(--accent-color)}
|
||||
.hover-bg-accent-color:hover {background-color: var(--accent-color)}
|
||||
|
||||
.accent-color-light {color: var(--accent-color-light)}
|
||||
.hover-accent-color-light:hover {color: var(--accent-color-light)}
|
||||
.bg-accent-color-light {background-color: var(--accent-color-light)}
|
||||
.hover-bg-accent-color-light:hover {background-color: var(--accent-color-light)}
|
||||
|
||||
.accent-color-dark {color: var(--accent-color-dark)}
|
||||
.bg-accent-color-dark {background-color: var(--accent-color-dark)}
|
||||
.hover-bg-accent-color-dark:hover {background-color: var(--accent-color-dark)}
|
||||
|
||||
.text-color-primary {color: var(--text-color-primary)}
|
||||
.text-on-primary-color {color: var(--text-on-primary-color)}
|
||||
.text-color-secondary {color: var(--text-color-secondary)}
|
||||
.text-color-disabled {color: var(--text-color-disabled)}
|
||||
.divider-color {color: var(--divider-color)}
|
||||
.warn-color {color: var(--warn-color)}
|
||||
|
||||
|
||||
.nested-links a {
|
||||
color: var(--primary-color);
|
||||
text-decoration: none;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
.column-count-2 {column-count: 1}
|
||||
.column-gap-1 {column-gap: 0}
|
||||
.break-inside-avoid {break-inside: auto}
|
||||
|
||||
|
||||
@media (--breakpoint-large) {
|
||||
.column-count-3-l {column-count: 3}
|
||||
.column-count-2-l {column-count: 2}
|
||||
.column-gap-1-l {column-gap: 1}
|
||||
.break-inside-avoid-l {break-inside: avoid}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
.prose table {
|
||||
width: 100%;
|
||||
margin-bottom: 3em;
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
font-size: 1em;
|
||||
border: 1px solid var(--light-gray);
|
||||
& th {
|
||||
background-color: var(--primary-color);
|
||||
border-bottom: 1px solid var(--primary-color);
|
||||
color: white;
|
||||
font-weight: 400;
|
||||
|
||||
text-align: left;
|
||||
padding: .375em .5em;
|
||||
}
|
||||
|
||||
& td, & tc {
|
||||
padding: .75em .5em;
|
||||
text-align: left;
|
||||
border-right: 1px solid var(--light-gray);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.prose table tr:nth-child(even) {
|
||||
background-color: var(--light-gray);
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
.prose ul, .prose ol {
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
.prose ul li, .prose ol li {
|
||||
margin-bottom: .5em;
|
||||
}
|
||||
.prose li:hover {
|
||||
background-color: var(--light-gray)
|
||||
}
|
||||
.prose ::selection {
|
||||
background: var(--primary-color); /* WebKit/Blink Browsers */
|
||||
color: white;
|
||||
}
|
||||
|
||||
.prose-glossary h3 {
|
||||
margin-top: 0;
|
||||
font-size: 1.125rem;
|
||||
}
|
||||
|
||||
.prose-glossary h3:first-of-type {
|
||||
margin-top: 3em;
|
||||
}
|
||||
|
||||
.prose-glossary h3 ~ p {
|
||||
margin: 0.5em 0 2em 0;
|
||||
}
|
||||
|
||||
body {
|
||||
|
||||
line-height: 1.45;
|
||||
|
||||
}
|
||||
|
||||
p {margin-bottom: 1.3em;}
|
||||
|
||||
h1, h2, h3, h4 {
|
||||
margin: 1.414em 0 0.5em;
|
||||
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin-top: 0;
|
||||
font-size: 2.441em;
|
||||
}
|
||||
|
||||
h2 {font-size: 1.953em;}
|
||||
|
||||
h3 {font-size: 1.563em;}
|
||||
|
||||
h4 {font-size: 1.25em;}
|
||||
|
||||
small, .font_small {font-size: 0.8em;}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
|
||||
dl dt {
|
||||
font-weight: bold;
|
||||
font-size: 1.125rem;
|
||||
}
|
||||
dd {
|
||||
margin: .5em 0 2em 0;
|
||||
padding: 0;
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
.note,
|
||||
.warning {
|
||||
|
||||
border-left-width: 4px;
|
||||
border-left-style: solid;
|
||||
position: relative;
|
||||
border-color: var(--primary-color);
|
||||
|
||||
display: block;
|
||||
}
|
||||
.note #exclamation-icon,
|
||||
.warning #exclamation-icon {
|
||||
|
||||
fill: var(--primary-color);
|
||||
position: absolute;
|
||||
top: 35%;
|
||||
left: -12px;
|
||||
/*background-color: white;*/
|
||||
}
|
||||
|
||||
.admonition-content {
|
||||
display: block;
|
||||
margin: 0px;
|
||||
padding: .125em 1em;
|
||||
/*margin-left: 1em;*/
|
||||
margin-top: 2em;
|
||||
margin-bottom: 2em;
|
||||
overflow-x: auto;
|
||||
/*font-size: .9375em;*/
|
||||
background-color: var(--black-05);
|
||||
}
|
||||
|
||||
|
||||
.hide-child-menu .child-menu {
|
||||
display: none;
|
||||
}
|
||||
.hide-child-menu:hover .child-menu,
|
||||
.hide-child-menu:focus .child-menu,
|
||||
.hide-child-menu:active .child-menu {
|
||||
display: block;
|
||||
}
|
||||
|
||||
|
||||
/*documentation-copy headings exaggerate spacing and size to chunk content */
|
||||
.documentation-copy h2 {
|
||||
margin-top: 3em;
|
||||
&.minor {
|
||||
font-size: inherit;
|
||||
margin-top: inherit;
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
.f2-fluid {
|
||||
font-size: 2.25rem;
|
||||
}
|
||||
|
||||
@media (--breakpoint-large) {
|
||||
.f2-fluid {
|
||||
font-size: 1.25rem;
|
||||
font-size: calc(0.875rem + 0.5 * ((100vw - 20rem) / 60));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/* From https://www.cssfontstack.com */
|
||||
code, .code, pre code, .highlight pre {
|
||||
font-family: 'inconsolata',Menlo,Monaco,'Courier New',monospace;
|
||||
}
|
||||
|
||||
.sans-serif {
|
||||
font-family: 'Muli', Avenir, 'Helvetica Neue', Helvetica, Roboto, Noto, 'Segoe UI', Arial, sans-serif;
|
||||
}
|
||||
|
||||
|
||||
.serif {
|
||||
font-family: Palatino,"Palatino Linotype","Palatino LT STD","Book Antiqua",Georgia,serif;
|
||||
}
|
||||
|
||||
/* Monospaced Typefaces (for code) */
|
||||
|
||||
|
||||
.courier {
|
||||
font-family: 'Courier Next',
|
||||
courier,
|
||||
monospace;
|
||||
}
|
||||
|
||||
|
||||
/* Sans-Serif Typefaces */
|
||||
|
||||
.helvetica {
|
||||
font-family: 'helvetica neue', helvetica,
|
||||
sans-serif;
|
||||
}
|
||||
|
||||
.avenir {
|
||||
font-family: 'avenir next', avenir,
|
||||
sans-serif;
|
||||
}
|
||||
|
||||
|
||||
/* Serif Typefaces */
|
||||
|
||||
.athelas {
|
||||
font-family: athelas,
|
||||
georgia,
|
||||
serif;
|
||||
}
|
||||
|
||||
.georgia {
|
||||
font-family: georgia,
|
||||
serif;
|
||||
}
|
||||
|
||||
.times {
|
||||
font-family: times,
|
||||
serif;
|
||||
}
|
||||
|
||||
.bodoni {
|
||||
font-family: "Bodoni MT",
|
||||
serif;
|
||||
}
|
||||
|
||||
.calisto {
|
||||
font-family: "Calisto MT",
|
||||
serif;
|
||||
}
|
||||
|
||||
.garamond {
|
||||
font-family: garamond,
|
||||
serif;
|
||||
}
|
||||
|
||||
.baskerville {
|
||||
font-family: baskerville,
|
||||
serif;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
.header-link:after {
|
||||
position: relative;
|
||||
left: 0.5em;
|
||||
opacity: 0;
|
||||
font-size: 0.8em;
|
||||
-moz-transition: opacity 0.2s ease-in-out 0.1s;
|
||||
-ms-transition: opacity 0.2s ease-in-out 0.1s;
|
||||
}
|
||||
h2:hover .header-link,
|
||||
h3:hover .header-link,
|
||||
h4:hover .header-link,
|
||||
h5:hover .header-link,
|
||||
h6:hover .header-link {
|
||||
opacity: 1;
|
||||
}
|
||||
Generated
+52
@@ -0,0 +1,52 @@
|
||||
/* pagination.html: https://github.com/gohugoio/hugo/blob/master/tpl/tplimpl/template_embedded.go#L117 */
|
||||
.pagination {
|
||||
margin: 3rem 0;
|
||||
}
|
||||
|
||||
.pagination li {
|
||||
display: inline-block;
|
||||
margin-right: .375rem;
|
||||
font-size: .875rem;
|
||||
margin-bottom: 2.5em;
|
||||
}
|
||||
.pagination li a {
|
||||
padding: .5rem .625rem;
|
||||
background-color: white;
|
||||
color: #333;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 3px;
|
||||
text-decoration: none;
|
||||
}
|
||||
.pagination li.disabled {
|
||||
display: none;
|
||||
}
|
||||
.pagination li.active a:link,
|
||||
.pagination li.active a:active,
|
||||
.pagination li.active a:visited {
|
||||
background-color: #ddd;
|
||||
}
|
||||
|
||||
/* Hides non-meaningful TOC items*/
|
||||
#TableOfContents ul li ul li ul li{
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
#TableOfContents ul li {
|
||||
color: black;
|
||||
display: block;
|
||||
margin-bottom: .375em;
|
||||
line-height: 1.375;
|
||||
}
|
||||
|
||||
#TableOfContents ul li a{
|
||||
width: 100%;
|
||||
padding: .25em .375em;
|
||||
margin-left: -.375em;
|
||||
|
||||
}
|
||||
#TableOfContents ul li a:hover {
|
||||
background-color: #999;
|
||||
color: white;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
.no-js .needs-js {
|
||||
opacity: 0
|
||||
}
|
||||
.js .needs-js {
|
||||
opacity: 1;
|
||||
transition: opacity .15s ease-in;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
@media print {
|
||||
#page-footer,
|
||||
body > footer,
|
||||
body > nav {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
#right-sidebar {
|
||||
scrollbar-width: none; /* hide scrollbar: Firefox */
|
||||
-ms-overflow-style: none; /* hide scrollbar: Internet Explorer 10+ */
|
||||
height: calc(100vh - 9rem);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
#right-sidebar::-webkit-scrollbar { /* hide scrollbar: WebKit */
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
Make h6 elements behave like dt elements. Initially implemented to support
|
||||
linkable glossary entries.
|
||||
|
||||
Yes, it's a hack. That's why it's in the shame file.
|
||||
*/
|
||||
|
||||
h6 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
font-size: 1.125rem;
|
||||
}
|
||||
|
||||
h6:first-of-type {
|
||||
margin-top: 3em;
|
||||
}
|
||||
|
||||
h6 ~ p {
|
||||
margin: 0.5em 0 2em 0;
|
||||
}
|
||||
|
||||
/* QR codes */
|
||||
img.qrcode {
|
||||
width: initial;
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
.facebook,
|
||||
.twitter,
|
||||
.instagram,
|
||||
.youtube {
|
||||
fill: #bababa;
|
||||
}
|
||||
.facebook:hover {
|
||||
fill: #3b5998;
|
||||
}
|
||||
|
||||
.twitter {
|
||||
fill: #55acee;
|
||||
}
|
||||
|
||||
.twitter:hover {
|
||||
fill: #bababa;
|
||||
}
|
||||
|
||||
.instagram:hover {
|
||||
fill: #e95950;
|
||||
}
|
||||
|
||||
.youtube:hover {
|
||||
fill: #bb0000;
|
||||
}
|
||||
|
||||
.mstdn {
|
||||
display: inline-block;
|
||||
background-color: #282c37;
|
||||
color: #d9e1e8;
|
||||
text-decoration: none;
|
||||
padding: 4px 10px 4px 30px;
|
||||
border-radius: 4px;
|
||||
font-size: 16px;
|
||||
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2261.076954mm%22%20height%3D%2265.47831mm%22%20viewBox%3D%220%200%20216.4144%20232.00976%22%3E%3Cpath%20d%3D%22M211.80734%20139.0875c-3.18125%2016.36625-28.4925%2034.2775-57.5625%2037.74875-15.15875%201.80875-30.08375%203.47125-45.99875%202.74125-26.0275-1.1925-46.565-6.2125-46.565-6.2125%200%202.53375.15625%204.94625.46875%207.2025%203.38375%2025.68625%2025.47%2027.225%2046.39125%2027.9425%2021.11625.7225%2039.91875-5.20625%2039.91875-5.20625l.8675%2019.09s-14.77%207.93125-41.08125%209.39c-14.50875.7975-32.52375-.365-53.50625-5.91875C9.23234%20213.82%201.40609%20165.31125.20859%20116.09125c-.365-14.61375-.14-28.39375-.14-39.91875%200-50.33%2032.97625-65.0825%2032.97625-65.0825C49.67234%203.45375%2078.20359.2425%20107.86484%200h.72875c29.66125.2425%2058.21125%203.45375%2074.8375%2011.09%200%200%2032.975%2014.7525%2032.975%2065.0825%200%200%20.41375%2037.13375-4.59875%2062.915%22%20fill%3D%22%233088d4%22%2F%3E%3Cpath%20d%3D%22M177.50984%2080.077v60.94125h-24.14375v-59.15c0-12.46875-5.24625-18.7975-15.74-18.7975-11.6025%200-17.4175%207.5075-17.4175%2022.3525v32.37625H96.20734V85.42325c0-14.845-5.81625-22.3525-17.41875-22.3525-10.49375%200-15.74%206.32875-15.74%2018.7975v59.15H38.90484V80.077c0-12.455%203.17125-22.3525%209.54125-29.675%206.56875-7.3225%2015.17125-11.07625%2025.85-11.07625%2012.355%200%2021.71125%204.74875%2027.8975%2014.2475l6.01375%2010.08125%206.015-10.08125c6.185-9.49875%2015.54125-14.2475%2027.8975-14.2475%2010.6775%200%2019.28%203.75375%2025.85%2011.07625%206.36875%207.3225%209.54%2017.22%209.54%2029.675%22%20fill%3D%22%23fff%22%2F%3E%3C%2Fsvg%3E");
|
||||
background-size: 16px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: top 50% left 8px;
|
||||
transition: all 0.5s;
|
||||
}
|
||||
.mstdn:hover {
|
||||
background-color: #484c56;
|
||||
}
|
||||
|
||||
.mstdn > span {
|
||||
color: #9baec8;
|
||||
font-size: 12px;
|
||||
padding-left: 3px;
|
||||
}
|
||||
.mstdn > span:before {
|
||||
content: "@";
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
|
||||
@media (min-width: 75em) {
|
||||
|
||||
[data-scrolldir="down"] .sticky {
|
||||
position: fixed;
|
||||
top:100px;
|
||||
right:0;
|
||||
}
|
||||
|
||||
[data-scrolldir="up"] .sticky {
|
||||
position: fixed;
|
||||
top:100px;
|
||||
right:0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
.fill-current { fill: currentColor; }
|
||||
@@ -0,0 +1,34 @@
|
||||
.tab-button{
|
||||
margin-bottom:1px;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
color:#333;
|
||||
border-color:#ccc;
|
||||
outline: none;
|
||||
background-color:white;
|
||||
}
|
||||
.tab-pane code{
|
||||
background:#f1f2f2;
|
||||
border-radius:0;
|
||||
}
|
||||
.tab-pane .chroma{
|
||||
background:none;
|
||||
padding:0;
|
||||
}
|
||||
.tab-button.active{
|
||||
border-bottom-color:#f1f2f2;
|
||||
background-color: #f1f2f2;
|
||||
}
|
||||
.tab-content .tab-pane{
|
||||
display: none;
|
||||
}
|
||||
.tab-content .tab-pane.active{
|
||||
display: block;
|
||||
}
|
||||
/* Treatment of copy buttons inside a tab module */
|
||||
.tab-content .copy, .tab-content .copied{
|
||||
display: none;
|
||||
}
|
||||
.tab-content .tab-pane.active + .copy, .tab-content .tab-pane.active + .copied{
|
||||
display: block;
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/*! TACHYONS v4.7.0 | http://tachyons.io */
|
||||
|
||||
/*
|
||||
* NOTE: The Tachyons folder is for backup/reference only. This file references the module
|
||||
* ________ ______
|
||||
* ___ __/_____ _________ /______ ______________________
|
||||
* __ / _ __ `/ ___/_ __ \_ / / / __ \_ __ \_ ___/
|
||||
* _ / / /_/ // /__ _ / / / /_/ // /_/ / / / /(__ )
|
||||
* /_/ \__,_/ \___/ /_/ /_/_\__, / \____//_/ /_//____/
|
||||
* /____/
|
||||
*
|
||||
* TABLE OF CONTENTS
|
||||
*
|
||||
* 1. External Library Includes
|
||||
* - Normalize.css | http://normalize.css.github.io
|
||||
* 2. Tachyons Modules
|
||||
* 3. Variables
|
||||
* - Media Queries
|
||||
* - Colors
|
||||
* 4. Debugging
|
||||
* - Debug all
|
||||
* - Debug children
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/* External Library Includes */
|
||||
@import 'tachyons/src/_normalize';
|
||||
|
||||
|
||||
/* Modules */
|
||||
@import 'tachyons/src/_box-sizing';
|
||||
/*@import 'tachyons/src/_aspect-ratios';*/
|
||||
@import 'tachyons/src/_images';
|
||||
@import 'tachyons/src/_background-size';
|
||||
@import 'tachyons/src/_background-position';
|
||||
/*@import 'tachyons/src/_outlines';*/
|
||||
@import 'tachyons/src/_borders';
|
||||
@import 'tachyons/src/_border-colors';
|
||||
@import 'tachyons/src/_border-radius';
|
||||
@import 'tachyons/src/_border-style';
|
||||
@import 'tachyons/src/_border-widths';
|
||||
@import 'tachyons/src/_box-shadow';
|
||||
/*@import 'tachyons/src/_code';*/
|
||||
@import 'tachyons/src/_coordinates';
|
||||
@import 'tachyons/src/_clears';
|
||||
@import 'tachyons/src/_display';
|
||||
@import 'tachyons/src/_flexbox';
|
||||
@import 'tachyons/src/_floats';
|
||||
/*@import 'tachyons/src/_font-family';*/
|
||||
@import 'tachyons/src/_font-style';
|
||||
@import 'tachyons/src/_font-weight';
|
||||
@import 'tachyons/src/_forms';
|
||||
@import 'tachyons/src/_heights';
|
||||
@import 'tachyons/src/_letter-spacing';
|
||||
@import 'tachyons/src/_line-height';
|
||||
@import 'tachyons/src/_links';
|
||||
@import 'tachyons/src/_lists';
|
||||
@import 'tachyons/src/_max-widths';
|
||||
@import 'tachyons/src/_widths';
|
||||
@import 'tachyons/src/_overflow';
|
||||
@import 'tachyons/src/_position';
|
||||
@import 'tachyons/src/_opacity';
|
||||
/*@import 'tachyons/src/_rotations';*/
|
||||
@import 'tachyons/src/_skins';
|
||||
@import 'tachyons/src/_skins-pseudo';
|
||||
@import 'tachyons/src/_spacing';
|
||||
@import 'tachyons/src/_negative-margins';
|
||||
@import 'tachyons/src/_tables';
|
||||
@import 'tachyons/src/_text-decoration';
|
||||
@import 'tachyons/src/_text-align';
|
||||
@import 'tachyons/src/_text-transform';
|
||||
@import 'tachyons/src/_type-scale';
|
||||
@import 'tachyons/src/_typography';
|
||||
@import 'tachyons/src/_utilities';
|
||||
@import 'tachyons/src/_visibility';
|
||||
@import 'tachyons/src/_white-space';
|
||||
@import 'tachyons/src/_vertical-align';
|
||||
@import 'tachyons/src/_hovers';
|
||||
@import 'tachyons/src/_z-index';
|
||||
@import 'tachyons/src/_nested';
|
||||
/*@import 'tachyons/src/_styles';*/
|
||||
|
||||
/* Variables */
|
||||
/* Importing here will allow you to override any variables in the modules */
|
||||
@import 'tachyons/src/_colors';
|
||||
@import 'tachyons/src/_media-queries';
|
||||
|
||||
/* Debugging */
|
||||
/*@import 'tachyons/src/_debug-children';
|
||||
@import 'tachyons/src/_debug-grid';*/
|
||||
|
||||
/* Uncomment out the line below to help debug layout issues */
|
||||
/* @import 'tachyons/src/_debug'; */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user