URI: 
       resources: Replace error handling in GetRemote with try (note) - hugo - [fork] hugo port for 9front
  HTML git clone git@git.drkhsh.at/hugo.git
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
   DIR README
   DIR LICENSE
       ---
   DIR commit 0918e087ec9dfe4b32011846313913e5c48f9475
   DIR parent 4ea94c451df9aaf85c03fb302662310e71f98677
  HTML Author: Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
       Date:   Sun,  5 Jan 2025 15:43:18 +0100
       
       resources: Replace error handling in GetRemote with try (note)
       
       Closes #13216
       
       Diffstat:
         M common/herrors/file_error.go        |      23 +++++++++++++++++++++--
         M hugolib/hugo_sites_build.go         |      14 +++++++++++++-
         M hugolib/page.go                     |       4 ----
         M hugolib/resource_chain_test.go      |      14 +++++++-------
         D resources/errorResource.go          |     145 -------------------------------
         M resources/page/page_nop.go          |       4 ----
         M resources/page/testhelpers_test.go  |       4 ----
         M resources/resource.go               |       7 -------
         M resources/resource/resourcetypes.go |      11 +++--------
         M resources/resource_factories/creat… |      20 ++++++++++----------
         M resources/transform.go              |       4 ----
         M tpl/internal/go_templates/texttemp… |      30 ++++++++++++++++++++++++++----
         M tpl/resources/resources.go          |      16 ++++++----------
         M tpl/tplimpl/embedded/templates/sho… |       8 ++++----
         M tpl/tplimpl/embedded/templates/sho… |      19 ++++++++++++++-----
         M tpl/tplimpl/embedded/templates/sho… |       8 ++++----
       
       16 files changed, 108 insertions(+), 223 deletions(-)
       ---
   DIR diff --git a/common/herrors/file_error.go b/common/herrors/file_error.go
       @@ -258,8 +258,27 @@ func openFile(filename string, fs afero.Fs) (afero.File, string, error) {
                return f, realFilename, nil
        }
        
       -// Cause returns the underlying error or itself if it does not implement Unwrap.
       +// Cause returns the underlying error, that is,
       +// it unwraps errors until it finds one that does not implement
       +// the Unwrap method.
       +// For a shallow variant, see Unwrap.
        func Cause(err error) error {
       +        type unwrapper interface {
       +                Unwrap() error
       +        }
       +
       +        for err != nil {
       +                cause, ok := err.(unwrapper)
       +                if !ok {
       +                        break
       +                }
       +                err = cause.Unwrap()
       +        }
       +        return err
       +}
       +
       +// Unwrap returns the underlying error or itself if it does not implement Unwrap.
       +func Unwrap(err error) error {
                if u := errors.Unwrap(err); u != nil {
                        return u
                }
       @@ -267,7 +286,7 @@ func Cause(err error) error {
        }
        
        func extractFileTypePos(err error) (string, text.Position) {
       -        err = Cause(err)
       +        err = Unwrap(err)
        
                var fileType string
        
   DIR diff --git a/hugolib/hugo_sites_build.go b/hugolib/hugo_sites_build.go
       @@ -343,6 +343,18 @@ func (h *HugoSites) render(l logg.LevelLogger, config *BuildCfg) error {
        
                siteRenderContext := &siteRenderContext{cfg: config, multihost: h.Configs.IsMultihost}
        
       +        renderErr := func(err error) error {
       +                if err == nil {
       +                        return nil
       +                }
       +                if strings.Contains(err.Error(), "can't evaluate field Err in type resource.Resource") {
       +                        // In Hugo 0.141.0 we replaced the special error handling for resources.GetRemote
       +                        // with the more general try.
       +                        return fmt.Errorf("%s: Resource.Err was removed in Hugo v0.141.0 and replaced with a new try keyword, see https://gohugo.io/functions/go-template/try/", err)
       +                }
       +                return err
       +        }
       +
                i := 0
                for _, s := range h.Sites {
                        segmentFilter := s.conf.C.SegmentFilter
       @@ -390,7 +402,7 @@ func (h *HugoSites) render(l logg.LevelLogger, config *BuildCfg) error {
                                                                }
                                                        } else {
                                                                if err := s.render(siteRenderContext); err != nil {
       -                                                                return err
       +                                                                return renderErr(err)
                                                                }
                                                        }
                                                        loggers.TimeTrackf(ll, start, nil, "")
   DIR diff --git a/hugolib/page.go b/hugolib/page.go
       @@ -185,10 +185,6 @@ func (p *pageState) isContentNodeBranch() bool {
                return p.IsNode()
        }
        
       -func (p *pageState) Err() resource.ResourceError {
       -        return nil
       -}
       -
        // Eq returns whether the current page equals the given page.
        // This is what's invoked when doing `{{ if eq $page $otherPage }}`
        func (p *pageState) Eq(other any) bool {
   DIR diff --git a/hugolib/resource_chain_test.go b/hugolib/resource_chain_test.go
       @@ -67,11 +67,11 @@ FIT: {{ $fit.Name }}|{{ $fit.RelPermalink }}|{{ $fit.Width }}
        CSS integrity Data first: {{ $cssFingerprinted1.Data.Integrity }} {{ $cssFingerprinted1.RelPermalink }}
        CSS integrity Data last:  {{ $cssFingerprinted2.RelPermalink }} {{ $cssFingerprinted2.Data.Integrity }}
        
       -{{ $failedImg := resources.GetRemote "%[1]s/fail.jpg" }}
       +{{ $failedImg := try (resources.GetRemote "%[1]s/fail.jpg") }}
        {{ $rimg := resources.GetRemote "%[1]s/sunset.jpg" }}
        {{ $remotenotfound := resources.GetRemote "%[1]s/notfound.jpg" }}
        {{ $localnotfound := resources.Get "images/notfound.jpg" }}
       -{{ $gopherprotocol := resources.GetRemote "gopher://example.org" }}
       +{{ $gopherprotocol := try (resources.GetRemote "gopher://example.org") }}
        {{ $rfit := $rimg.Fit "200x200" }}
        {{ $rfit2 := $rfit.Fit "100x200" }}
        {{ $rimg = $rimg | fingerprint }}
       @@ -79,10 +79,10 @@ SUNSET REMOTE: {{ $rimg.Name }}|{{ $rimg.RelPermalink }}|{{ $rimg.Width }}|{{ le
        FIT REMOTE: {{ $rfit.Name }}|{{ $rfit.RelPermalink }}|{{ $rfit.Width }}
        REMOTE NOT FOUND: {{ if $remotenotfound }}FAILED{{ else}}OK{{ end }}
        LOCAL NOT FOUND: {{ if $localnotfound }}FAILED{{ else}}OK{{ end }}
       -PRINT PROTOCOL ERROR1: {{ with $gopherprotocol }}{{ . | safeHTML }}{{ end }}
       +PRINT PROTOCOL ERROR1: {{ with $gopherprotocol }}{{ .Value | safeHTML }}{{ end }}
        PRINT PROTOCOL ERROR2: {{ with $gopherprotocol }}{{ .Err | safeHTML }}{{ end }}
       -PRINT PROTOCOL ERROR DETAILS: {{ with $gopherprotocol }}Err: {{ .Err | safeHTML }}{{ with .Err }}|{{ with .Data }}Body: {{ .Body }}|StatusCode: {{ .StatusCode }}{{ end }}|{{ end }}{{ end }}
       -FAILED REMOTE ERROR DETAILS CONTENT: {{ with $failedImg.Err }}|{{ . }}|{{ with .Data }}Body: {{ .Body }}|StatusCode: {{ .StatusCode }}|ContentLength: {{ .ContentLength }}|ContentType: {{ .ContentType }}{{ end }}{{ end }}|
       +PRINT PROTOCOL ERROR DETAILS: {{ with $gopherprotocol }}{{ with .Err }}Err: {{ . | safeHTML }}{{ with .Cause }}|{{ with .Data }}Body: {{ .Body }}|StatusCode: {{ .StatusCode }}{{ end }}|{{ end }}{{ end }}{{ end }}
       +FAILED REMOTE ERROR DETAILS CONTENT: {{ with $failedImg }}{{ with .Err }}{{ with .Cause }}{{ . }}|{{ with .Data }}Body: {{ .Body }}|StatusCode: {{ .StatusCode }}|ContentLength: {{ .ContentLength }}|ContentType: {{ .ContentType }}{{ end }}{{ end }}{{ end }}{{ end }}|
        `, ts.URL))
        
                fs := b.Fs.Source
       @@ -114,8 +114,8 @@ SUNSET REMOTE: /sunset_%[1]s.jpg|/sunset_%[1]s.a9bf1d944e19c0f382e0d8f51de690f7d
        FIT REMOTE: /sunset_%[1]s.jpg|/sunset_%[1]s_hu15210517121918042184.jpg|200
        REMOTE NOT FOUND: OK
        LOCAL NOT FOUND: OK
       -PRINT PROTOCOL ERROR DETAILS: Err: error calling resources.GetRemote: Get "gopher://example.org": unsupported protocol scheme "gopher"||
       -FAILED REMOTE ERROR DETAILS CONTENT: |failed to fetch remote resource from &#39;%[2]s/fail.jpg&#39;: Not Implemented|Body: { msg: failed }
       +PRINT PROTOCOL ERROR DETAILS: Err: template: index.html:22:36: executing "index.html" at <resources.GetRemote>: error calling GetRemote: Get "gopher://example.org": unsupported protocol scheme "gopher"|
       +FAILED REMOTE ERROR DETAILS CONTENT: failed to fetch remote resource from &#39;%[2]s/fail.jpg&#39;: Not Implemented|Body: { msg: failed }
        |StatusCode: 501|ContentLength: 16|ContentType: text/plain; charset=utf-8|
        
        
   DIR diff --git a/resources/errorResource.go b/resources/errorResource.go
       @@ -1,145 +0,0 @@
       -// Copyright 2021 The Hugo Authors. All rights reserved.
       -//
       -// 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.
       -
       -package resources
       -
       -import (
       -        "context"
       -        "image"
       -
       -        "github.com/gohugoio/hugo/common/hugio"
       -        "github.com/gohugoio/hugo/common/maps"
       -        "github.com/gohugoio/hugo/media"
       -        "github.com/gohugoio/hugo/resources/images"
       -        "github.com/gohugoio/hugo/resources/images/exif"
       -        "github.com/gohugoio/hugo/resources/resource"
       -)
       -
       -var (
       -        _ error = (*errorResource)(nil)
       -        // Image covers all current Resource implementations.
       -        _ images.ImageResource = (*errorResource)(nil)
       -        // The list of user facing and exported interfaces in resource.go
       -        // Note that if we're missing some interface here, the user will still
       -        // get an error, but not as pretty.
       -        _ resource.ContentResource         = (*errorResource)(nil)
       -        _ resource.ReadSeekCloserResource  = (*errorResource)(nil)
       -        _ resource.ResourcesLanguageMerger = (*resource.Resources)(nil)
       -        // Make sure it also fails when passed to a pipe function.
       -        _ ResourceTransformer = (*errorResource)(nil)
       -)
       -
       -// NewErrorResource wraps err in a Resource where all but the Err method will panic.
       -func NewErrorResource(err resource.ResourceError) resource.Resource {
       -        return &errorResource{ResourceError: err}
       -}
       -
       -type errorResource struct {
       -        resource.ResourceError
       -}
       -
       -func (e *errorResource) Err() resource.ResourceError {
       -        return e.ResourceError
       -}
       -
       -func (e *errorResource) ReadSeekCloser() (hugio.ReadSeekCloser, error) {
       -        panic(e.ResourceError)
       -}
       -
       -func (e *errorResource) Content(context.Context) (any, error) {
       -        panic(e.ResourceError)
       -}
       -
       -func (e *errorResource) ResourceType() string {
       -        panic(e.ResourceError)
       -}
       -
       -func (e *errorResource) MediaType() media.Type {
       -        panic(e.ResourceError)
       -}
       -
       -func (e *errorResource) Permalink() string {
       -        panic(e.ResourceError)
       -}
       -
       -func (e *errorResource) RelPermalink() string {
       -        panic(e.ResourceError)
       -}
       -
       -func (e *errorResource) Name() string {
       -        panic(e.ResourceError)
       -}
       -
       -func (e *errorResource) Title() string {
       -        panic(e.ResourceError)
       -}
       -
       -func (e *errorResource) Params() maps.Params {
       -        panic(e.ResourceError)
       -}
       -
       -func (e *errorResource) Data() any {
       -        panic(e.ResourceError)
       -}
       -
       -func (e *errorResource) Height() int {
       -        panic(e.ResourceError)
       -}
       -
       -func (e *errorResource) Width() int {
       -        panic(e.ResourceError)
       -}
       -
       -func (e *errorResource) Process(spec string) (images.ImageResource, error) {
       -        panic(e.ResourceError)
       -}
       -
       -func (e *errorResource) Crop(spec string) (images.ImageResource, error) {
       -        panic(e.ResourceError)
       -}
       -
       -func (e *errorResource) Fill(spec string) (images.ImageResource, error) {
       -        panic(e.ResourceError)
       -}
       -
       -func (e *errorResource) Fit(spec string) (images.ImageResource, error) {
       -        panic(e.ResourceError)
       -}
       -
       -func (e *errorResource) Resize(spec string) (images.ImageResource, error) {
       -        panic(e.ResourceError)
       -}
       -
       -func (e *errorResource) Filter(filters ...any) (images.ImageResource, error) {
       -        panic(e.ResourceError)
       -}
       -
       -func (e *errorResource) Exif() *exif.ExifInfo {
       -        panic(e.ResourceError)
       -}
       -
       -func (e *errorResource) Colors() ([]images.Color, error) {
       -        panic(e.ResourceError)
       -}
       -
       -func (e *errorResource) DecodeImage() (image.Image, error) {
       -        panic(e.ResourceError)
       -}
       -
       -func (e *errorResource) Transform(...ResourceTransformation) (ResourceTransformer, error) {
       -        panic(e.ResourceError)
       -}
       -
       -func (e *errorResource) TransformWithContext(context.Context, ...ResourceTransformation) (ResourceTransformer, error) {
       -        panic(e.ResourceError)
       -}
   DIR diff --git a/resources/page/page_nop.go b/resources/page/page_nop.go
       @@ -61,10 +61,6 @@ type nopPage int
        
        var noOpPathInfo = media.DefaultPathParser.Parse(files.ComponentFolderContent, "no-op.md")
        
       -func (p *nopPage) Err() resource.ResourceError {
       -        return nil
       -}
       -
        func (p *nopPage) Aliases() []string {
                return nil
        }
   DIR diff --git a/resources/page/testhelpers_test.go b/resources/page/testhelpers_test.go
       @@ -111,10 +111,6 @@ type testPage struct {
                sectionEntries []string
        }
        
       -func (p *testPage) Err() resource.ResourceError {
       -        return nil
       -}
       -
        func (p *testPage) Aliases() []string {
                panic("testpage: not implemented")
        }
   DIR diff --git a/resources/resource.go b/resources/resource.go
       @@ -224,9 +224,6 @@ type resourceCopier interface {
        
        // Copy copies r to the targetPath given.
        func Copy(r resource.Resource, targetPath string) resource.Resource {
       -        if r.Err() != nil {
       -                panic(fmt.Sprintf("Resource has an .Err: %s", r.Err()))
       -        }
                return r.(resourceCopier).cloneTo(targetPath)
        }
        
       @@ -439,10 +436,6 @@ func (l *genericResource) Content(context.Context) (any, error) {
                return hugio.ReadString(r)
        }
        
       -func (r *genericResource) Err() resource.ResourceError {
       -        return nil
       -}
       -
        func (l *genericResource) Data() any {
                return l.sd.Data
        }
   DIR diff --git a/resources/resource/resourcetypes.go b/resources/resource/resourcetypes.go
       @@ -43,6 +43,9 @@ type OriginProvider interface {
        
        // NewResourceError creates a new ResourceError.
        func NewResourceError(err error, data any) ResourceError {
       +        if data == nil {
       +                data = map[string]any{}
       +        }
                return &resourceError{
                        error: err,
                        data:  data,
       @@ -65,13 +68,6 @@ type ResourceError interface {
                ResourceDataProvider
        }
        
       -// ErrProvider provides an Err.
       -type ErrProvider interface {
       -        // Err returns an error if this resource is in an error state.
       -        // This will currently only be set for resources obtained from resources.GetRemote.
       -        Err() ResourceError
       -}
       -
        // Resource represents a linkable resource, i.e. a content page, image etc.
        type Resource interface {
                ResourceWithoutMeta
       @@ -83,7 +79,6 @@ type ResourceWithoutMeta interface {
                MediaTypeProvider
                ResourceLinksProvider
                ResourceDataProvider
       -        ErrProvider
        }
        
        type ResourceWrapper interface {
   DIR diff --git a/resources/resource_factories/create/create_integration_test.go b/resources/resource_factories/create/create_integration_test.go
       @@ -31,18 +31,17 @@ func TestGetRemoteHead(t *testing.T) {
          [security.http]
            methods = ['(?i)GET|POST|HEAD']
            urls = ['.*gohugo\.io.*']
       -
        -- layouts/index.html --
        {{ $url := "https://gohugo.io/img/hugo.png" }}
        {{ $opts := dict "method" "head" }}
       -{{ with resources.GetRemote $url $opts }}
       +{{ with try (resources.GetRemote $url $opts) }}
          {{ with .Err }}
            {{ errorf "Unable to get remote resource: %s" . }}
       -  {{ else }}
       +  {{ else with .Value }}
            Head Content: {{ .Content }}. Head Data: {{ .Data }}
       -  {{ end }}
       -{{ else }}
       +  {{ else }}
          {{ errorf "Unable to get remote resource: %s" $url }}
       +  {{ end }}
        {{ end }}
        `
        
       @@ -90,14 +89,15 @@ mediaTypes = ['text/plain']
        -- layouts/_default/single.html --
        {{ $url := printf "%s%s" "URL" .RelPermalink}}
        {{ $opts := dict }}
       -{{ with resources.GetRemote $url $opts }}
       +{{ with try (resources.GetRemote $url $opts) }}
          {{ with .Err }}
       -    {{ errorf "Got Err: %s. Data: %v" . .Data }}
       -  {{ else }}
       +     {{ errorf "Got Err: %s" . }}
       +         {{ with .Cause }}{{ errorf "Data: %s" .Data }}{{ end }}
       +  {{ else with .Value }}
            Content: {{ .Content }}
       +  {{ else }}
       +    {{ errorf "Unable to get remote resource: %s" $url }}
          {{ end }}
       -{{ else }}
       -  {{ errorf "Unable to get remote resource: %s" $url }}
        {{ end }}
        `
        
   DIR diff --git a/resources/transform.go b/resources/transform.go
       @@ -192,10 +192,6 @@ func (r *resourceAdapter) Content(ctx context.Context) (any, error) {
                return r.target.Content(ctx)
        }
        
       -func (r *resourceAdapter) Err() resource.ResourceError {
       -        return nil
       -}
       -
        func (r *resourceAdapter) GetIdentity() identity.Identity {
                return identity.FirstIdentity(r.target)
        }
   DIR diff --git a/tpl/internal/go_templates/texttemplate/hugo_template.go b/tpl/internal/go_templates/texttemplate/hugo_template.go
       @@ -19,6 +19,7 @@ import (
                "io"
                "reflect"
        
       +        "github.com/gohugoio/hugo/common/herrors"
                "github.com/gohugoio/hugo/common/hreflect"
        
                "github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate/parse"
       @@ -256,14 +257,34 @@ func (s *state) evalField(dot reflect.Value, fieldName string, node parse.Node, 
                panic("not reached")
        }
        
       +// newErrorWithCause creates a new error with the given cause.
       +func newErrorWithCause(err error) *TryError {
       +        return &TryError{Err: err, Cause: herrors.Cause(err)}
       +}
       +
       +// TryError wraps an error with a cause.
       +type TryError struct {
       +        Err   error
       +        Cause error
       +}
       +
       +func (e *TryError) Error() string {
       +        return e.Err.Error()
       +}
       +
       +func (e *TryError) Unwrap() error {
       +        return e.Err
       +}
       +
        // TryValue is what gets returned when using the "try" keyword.
        type TryValue struct {
                // Value is the value returned by the function or method wrapped with "try".
                // This will always be nil if Err is set.
                Value any
       +
                // Err is the error returned by the function or method wrapped with "try".
                // This will always be nil if Value is set.
       -        Err error
       +        Err *TryError
        }
        
        // evalCall executes a function or method call. If it's a method, fun already has the receiver bound, so
       @@ -274,10 +295,11 @@ func (s *state) evalCall(dot, fun reflect.Value, isBuiltin bool, node parse.Node
                if name == "try" {
                        defer func() {
                                if r := recover(); r != nil {
       +                                // Cause: herrors.Cause(err)
                                        if err, ok := r.(error); ok {
       -                                        val = reflect.ValueOf(TryValue{nil, err})
       +                                        val = reflect.ValueOf(TryValue{Value: nil, Err: newErrorWithCause(err)})
                                        } else {
       -                                        val = reflect.ValueOf(TryValue{nil, fmt.Errorf("%v", r)})
       +                                        val = reflect.ValueOf(TryValue{Value: nil, Err: newErrorWithCause(fmt.Errorf("%v", r))})
                                        }
                                }
                        }()
       @@ -396,7 +418,7 @@ func (s *state) evalCall(dot, fun reflect.Value, isBuiltin bool, node parse.Node
        
                // Added for Hugo.
                if name == "try" {
       -                return reflect.ValueOf(TryValue{vv.Interface(), nil})
       +                return reflect.ValueOf(TryValue{Value: vv.Interface()})
                }
        
                return vv
   DIR diff --git a/tpl/resources/resources.go b/tpl/resources/resources.go
       @@ -115,14 +115,10 @@ func (ns *Namespace) Get(filename any) resource.Resource {
        //
        // Note: This method does not return any error as a second return value,
        // for any error situations the error can be checked in .Err.
       -func (ns *Namespace) GetRemote(args ...any) resource.Resource {
       +func (ns *Namespace) GetRemote(args ...any) (resource.Resource, error) {
                get := func(args ...any) (resource.Resource, error) {
       -                if len(args) < 1 {
       -                        return nil, errors.New("must provide an URL")
       -                }
       -
       -                if len(args) > 2 {
       -                        return nil, errors.New("must not provide more arguments than URL and options")
       +                if len(args) < 1 || len(args) > 2 {
       +                        return nil, errors.New("must provide an URL and optionally an options map")
                        }
        
                        urlstr, err := cast.ToStringE(args[0])
       @@ -146,12 +142,12 @@ func (ns *Namespace) GetRemote(args ...any) resource.Resource {
                if err != nil {
                        switch v := err.(type) {
                        case *create.HTTPError:
       -                        return resources.NewErrorResource(resource.NewResourceError(v, v.Data))
       +                        return nil, resource.NewResourceError(v, v.Data)
                        default:
       -                        return resources.NewErrorResource(resource.NewResourceError(fmt.Errorf("error calling resources.GetRemote: %w", err), make(map[string]any)))
       +                        return nil, resource.NewResourceError(err, nil)
                        }
                }
       -        return r
       +        return r, nil
        }
        
        // GetMatch finds the first Resource matching the given pattern, or nil if none found.
   DIR diff --git a/tpl/tplimpl/embedded/templates/shortcodes/twitter.html b/tpl/tplimpl/embedded/templates/shortcodes/twitter.html
       @@ -17,13 +17,13 @@
          {{- $url := printf "https://twitter.com/%v/status/%v" .user .id -}}
          {{- $query := querify "url" $url "dnt" .dnt -}}
          {{- $request := printf "https://publish.twitter.com/oembed?%s" $query -}}
       -  {{- with resources.GetRemote $request -}}
       +  {{- with try (resources.GetRemote $request) -}}
            {{- with .Err -}}
              {{- errorf "%s" . -}}
       -    {{- else -}}
       +    {{- else with .Value -}}
              {{- (. | transform.Unmarshal).html | safeHTML -}}
       -    {{- end -}}
       -  {{- else -}}
       +    {{- else -}}
            {{- warnidf "shortcode-twitter-getremote" "The %q shortcode was unable to retrieve the remote data. See %s" .name .position -}}
       +    {{- end -}}
          {{- end -}}
        {{- end -}}
   DIR diff --git a/tpl/tplimpl/embedded/templates/shortcodes/twitter_simple.html b/tpl/tplimpl/embedded/templates/shortcodes/twitter_simple.html
       @@ -14,14 +14,14 @@
          {{- $url := printf "https://twitter.com/%v/status/%v" .user .id -}}
          {{- $query := querify "url" $url "dnt" .dnt "omit_script" true -}}
          {{- $request := printf "https://publish.twitter.com/oembed?%s" $query -}}
       -  {{- with resources.GetRemote $request -}}
       +  {{- with try (resources.GetRemote $request) -}}
            {{- with .Err -}}
              {{- errorf "%s" . -}}
       -    {{- else -}}
       +    {{- else with .Value -}}
              {{- (. | transform.Unmarshal).html | safeHTML -}}
       +    {{- else -}}
       +      {{- warnidf "shortcode-twitter-simple-getremote" "The %q shortcode was unable to retrieve the remote data. See %s" .name .position -}}
            {{- end -}}
       -  {{- else -}}
       -    {{- warnidf "shortcode-twitter-simple-getremote" "The %q shortcode was unable to retrieve the remote data. See %s" .name .position -}}
          {{- end -}}
        {{- end -}}
        
       @@ -31,7 +31,16 @@
            {{- .Page.Scratch.Set "__h_simple_twitter_css" true -}}
            <style type="text/css">
              .twitter-tweet {
       -        font: 14px/1.45 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;
       +        font:
       +          14px/1.45 -apple-system,
       +          BlinkMacSystemFont,
       +          "Segoe UI",
       +          Roboto,
       +          Oxygen-Sans,
       +          Ubuntu,
       +          Cantarell,
       +          "Helvetica Neue",
       +          sans-serif;
                border-left: 4px solid #2b7bb9;
                padding-left: 1.5em;
                color: #555;
   DIR diff --git a/tpl/tplimpl/embedded/templates/shortcodes/vimeo_simple.html b/tpl/tplimpl/embedded/templates/shortcodes/vimeo_simple.html
       @@ -23,10 +23,10 @@
          {{- $url := urls.JoinPath "https://vimeo.com" .id -}}
          {{- $query := querify "url" $url "dnt" $dnt -}}
          {{- $request := printf "https://vimeo.com/api/oembed.json?%s" $query -}}
       -  {{- with resources.GetRemote $request -}}
       +  {{- with try (resources.GetRemote $request) -}}
            {{- with .Err -}}
              {{- errorf "%s" . -}}
       -    {{- else -}}
       +    {{- else with .Value -}}
              {{- with . | transform.Unmarshal -}}
                {{- $class := printf "%s %s" "s_video_simple" "__h_video" -}}
                {{- with $.class -}}
       @@ -45,8 +45,8 @@
                  </a>
                </div>
              {{- end -}}
       +    {{- else -}}
       +      {{- warnidf "shortcode-vimeo-simple" "The %q shortcode was unable to retrieve the remote data. See %s" .name .position -}}
            {{- end -}}
       -  {{- else -}}
       -    {{- warnidf "shortcode-vimeo-simple" "The %q shortcode was unable to retrieve the remote data. See %s" .name .position -}}
          {{- end -}}
        {{- end -}}