Shortcode for pasting multiple snippets from single file

Hello, I want to make a shortcode which allows me to paste multiple snippets from single file by their id.

I.e. I want to place that file in static folder:

// START full
func NewGame() *Game {
	// START root
	root := widget.NewContainer(
		widget.ContainerOpts.BackgroundImage(
			image.NewNineSliceColor(colornames.Gainsboro),
		),
	)
	// END root
	return &Game{
		ui: &ebitenui.UI{Container: root},
	}
}
// END full

And pull different snippets from it, like this:

{{< code source="static/examples/bas_con_sin.txt" language="go" id="full">}}
func NewGame() *Game {
	root := widget.NewContainer(
		widget.ContainerOpts.BackgroundImage(
			image.NewNineSliceColor(colornames.Gainsboro),
		),
	)
	return &Game{
		ui: &ebitenui.UI{Container: root},
	}
}

And this:

{{< code source="static/examples/bas_con_sin.txt" language="go" id="root">}}
root := widget.NewContainer(
	widget.ContainerOpts.BackgroundImage(
		image.NewNineSliceColor(colornames.Gainsboro),
	),
)

I have written a shortcode for that, but its not removing nested indents:

{{ $file := .Get "source" }}
{{ $id := .Get "id" }}
{{ $lang := .Get "language" }}
{{ $content := readFile $file }}

{{ $snippetStart := printf "// START %s" $id }}
{{ $snippetEnd := printf "// END %s" $id }}

{{ $inSnippet := false }}
{{ $snippet := "" }}

{{ range $line := split $content "\n" }}
{{ $trimmedLine := trim $line " \t\n\r" }}

{{ if eq $trimmedLine $snippetStart }}
{{ $inSnippet = true }}
{{ continue }}
{{ end }}

{{ if eq $trimmedLine $snippetEnd }}
{{ $inSnippet = false }}
{{ continue }}
{{ end }}

{{ if $inSnippet }}
<!-- Skip any nested START/END markers inside the snippet -->
{{ if not (or (findRE "^// START " $trimmedLine) (findRE "^// END " $trimmedLine)) }}
{{ $snippet = printf "%s%s\n" $snippet $line }}
{{ end }}
{{ end }}
{{ end }}

{{ $snippet := trim $snippet "\n" }}

{{ if $snippet }}
{{ $highlighted := highlight $snippet $lang "" }}
{{ $highlighted | safeHTML }}
{{ else }}
<p>No snippet found for id "{{ $id }}"</p>
{{ end }}

I’m struggle with nested indents a bit. Does someone knows, how to remove them properly?

with the following conditions:

  • your source file is not using different indentation chars for the lines
  • your START tag is indented to the level that has to be removed

you could:

  • catch the whitespace of the preceding your // START tag
  • remove the same amount of whitespace from all printed lines
{{ range $line := split $content "\n" }}
   {{ $trimmedLine := trim $line " \t\n\r" }}
   {{ if eq $trimmedLine $snippetStart }}
      <!-- capture indentation space as pattern -->
      {{ $indent = printf "^%s" (index (findRE `^\s*` $line) 0) }}       
      {{ $inSnippet = true }}
      {{ continue }}
   {{ end }}

   {{ if eq $trimmedLine $snippetEnd }}
      {{ $inSnippet = false }}
      {{ continue }}
   {{ end }}

   {{ if $inSnippet }}
      <!-- Skip any nested START/END markers inside the snippet -->
      {{ if not (or (findRE "^// START " $trimmedLine) (findRE "^// END " $trimmedLine)) }}
                                                <!--  remove the indent from the line -->
         {{ $snippet = printf "%s%s\n" $snippet (replaceRE $indent "" $line) }}
      {{ end }}
   {{ end }}
{{ end }}

update - played a litte with regex :wink:

Regex variant
{{ $file := .Get "source" }}
{{ $id := .Get "id" }}
{{ $lang := .Get "language" }}
{{ $content := readFile $file }}


<!-- captures the text between start and end tag -->
{{ $blockPattern := printf `(?s)^.*?\n?(\s*)// START %s\s*\n(.*?)\n\s*// END %s\s*\n` $id $id }}
<!-- captures all start and end tags -->
{{ $tagPattern := printf `(^|\n)\s*// (START|END)\s+\w+` }}


<!-- find a matching block (in fact this finds all with same $id but only uses the first one ) -->
{{ with findRESubmatch $blockPattern $content }}
   <!-- always an array, so get the first match -->
   {{ with index . 0 }}
      <!-- now the . is the array of matches
         IDX 0 : full text
         IDX 1 : whitespace indent before START tag
         IDX 2 : the code without START and END tag lines
        -->

      <!-- create a pattern for the indentation to be removed -->
      {{ $indentRemovePattern := printf `(?s)(^|\n)%s` (index . 1) }}
      <!-- remove all nested tags -->
      {{ $snippet := replaceRE $tagPattern "" (index . 2) }}
      <!-- remove indentation -->
      {{ $snippet = replaceRE $indentRemovePattern "$1" $snippet }}
      <!-- highlight (trim just for safety) -->
      {{ highlight (trim $snippet " \t\n" ) $lang "" }}
   {{ end }}

{{ else }}
   <p>No snippet found for id "{{ $id }}"</p>
{{ end }}

2 Likes

Thanks a lot for this, its working great!
I also noticed that hugo serve needs to be restarted in order to see the file updates, is it possible to to something with it?

I can imagine this has something to do cause your files are in static folder. Static is not ment to be processed but copied as is…

As bep mentioned in the other issue. You should better use resources (global or page) maybe mounts and use the resource instead of os.readFile

And global resources are /assets, right?

right

Thanks for the last shortcode.
I wonder is it possible to also skip some unwanted content like this:

// START full
root := widget.NewContainer(
    // SKIP-START full
	widget.ContainerOpts.BackgroundImage(
		image.NewNineSliceColor(assets.ColorL),
	),
    // SKIP-END full
    widget.ContainerOpts.Layout(widget.NewAnchorLayout(
        widget.AnchorLayoutOpts.Padding(widget.Insets{
            Left: 50,
        }),
    )),
)
// END full

In order to get is skipped only for “full” id:

root := widget.NewContainer(
    widget.ContainerOpts.Layout(widget.NewAnchorLayout(
        widget.AnchorLayoutOpts.Padding(widget.Insets{
            Left: 50,
        }),
    )),
)

Just adapt the $blockpattern tags and replacere inside the with index 0`

Just try to get it running…if not create e new topic.

1 Like

Ok, I’ll try, thanks for you time and help.

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.