The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package SnipMate::Snippets;

use 5.14.0;

use strict;
use warnings;

use Method::Signatures;

use Moose;

use MooseX::Types::Path::Class;

use Template::Caribou::Utils;

use Template::Caribou::Tags::HTML qw/ :all /;

use Template::Caribou::Tags
    mytag => { -as => 'span_placeholder', class => 'placeholder', tag => 'span' },
    map { ( mytag => { -as => "div_$_", class => $_ } ) } qw/
        comment code snippet keyword snippets header
    /
    ;


with 'Template::Caribou';

has snippet_file => (
    is => 'ro',
    isa => 'Path::Class::File',
    coerce => 1,
    required => 1,
);

has snippets => (
    is => 'ro',
    lazy => 1,
    builder => '_build_snippets',
);


method _build_snippets {
    my @lines = $self->snippet_file->slurp;

    my @all_snippets;
    my $current_title;
    my @current_snippets;

    my $i = -1;
    LINE:
    while( my $line = $lines[++$i] ) {
        if ( $line =~ s/^##\s*(.*?)\s*/$1/ ) {
            if ( @current_snippets ) {
                push @all_snippets, [ $current_title => @current_snippets ];
            }
            $current_title = $line;
            @current_snippets = ();
            next LINE;
        }

        if ( $line =~ s/^\s*snippet\s+(.*)// ) {
            my $snippet = $1;
            my $comment;
            if ( $i > 0 and $lines[$i-1] =~ /^#(.*)/ ) {
                $comment = $1;
            }
            my $code = $lines[++$i];
            $code =~ s/^(\s+)//;
            my $spaces = $1;
            $code .= $lines[$i] while $lines[++$i] =~ s/^$spaces//;

            push @current_snippets, [ $snippet, $comment, $code ];
        }
    }

    push @all_snippets, [ $current_title => @current_snippets ] 
        if @current_snippets;

    return \@all_snippets;

}

template webpage => method {
    html {
        head { 
            show('style');
        };
        body { 
            h1 {  $self->snippet_file->basename };
            div_snippets {
                show( 'section' => @$_ ) for @{ $self->snippets };
            }
        };
    }
};

template section => method( $title,@snippets ) {

    h2 { $title } if $title;

    show( 'snippet' => @$_ ) for @snippets;
};

template snippet => method ( $label, $comment, $code ) {
    div_snippet {
        div_header { 
            div_keyword { $label; };
            div_comment { $comment; };
        };
        div_code sub {
            my $regex = qr#(\$\{\d+.*?\})#;

            for ( split $regex, $code ) {
                if ( /$regex/ ) {
                    span_placeholder { $_ };
                }
                else {
                    print $_;
                }
            }
        };
    }

};

template style => sub {
    css <<'END_CSS';

@page { size: landscape; }

body {
    font-family: monospace;
}

h2 { 
    background-color: 
    darkblue; color: white; 
    padding: 3px;
    text-align: center;
}

.header { border-bottom: 1px black solid; }

.keyword {
    display: inline-block;
    font-size: 1.5em;
}

.comment {
    float: right;
    font-style: italic;
}

.desc {
    margin-top: 0.5em;
}

.code {
    padding-left: 0.5em;
    white-space: pre;
    margin-top: 1em;
    overflow: hidden;
}

.placeholder {
   color: red;
}

.snippets {
    -moz-column-count: 3;
    -moz-column-gap: 20px;
    -moz-column-rule: 1px solid black;
}

.snippet {
    column-break-inside: avoid; /* doesn't work. boo */
    display: inline-block;      /* workaround for column-break suckiness */
    width: 100%;
    margin-bottom: 1em;
}

END_CSS

};

__PACKAGE__->meta->make_immutable;

1;