#!/usr/bin/perl
# Copyright © 2011-2025 Jon Dowland <jon@dow.land>
# Licensed under the GNU GPL, version 2, or any later version published by the
# Free Software Foundation

package IkiWiki::Plugin::pagespec_alias;

use warnings;
use strict;
use IkiWiki '3.00';

sub import {
  hook(type => "getsetup", id=> "pagespec_alias", call => \&getsetup);
  hook(type => "checkconfig", id=> "pagespec_alias", call => \&checkconfig);
}

sub getsetup () {
    return
        plugin => {
            description => "define aliases to PageSpecs to ease re-use",
            safe => 0,
            rebuild => 1,
            section => "link",
        },
        pagespec_aliases => {
            type => "string",
            example => { image => "*.png or *.jpg or *.gif" },
            description => "a list of alias: PageSpec mappings",
            safe => 1,
            rebuild => 0,
        },
}

# ensure user-defined PageSpec aliases are composed of word-characters only
sub safe_key {
  my $key = shift;
  return 1 if $key =~ /^\w+$/;
  0;
}

my $checkconfig_singleton;

sub checkconfig () {
    # IkIWiki can run checkconfig more than once in some situations.
    # We need to ensure the aliases are only defined once.
    return if $checkconfig_singleton;

    if ($config{pagespec_aliases}) {
        define_aliases();
        $checkconfig_singleton = 1;
    }
}

sub define_aliases () {
    no strict 'refs';

    foreach my $key (keys %{$config{pagespec_aliases}}) {
        error(gettext("Only word-characters are permitted in PageSpec aliases"))
            unless safe_key($key);
        my $value = ${$config{pagespec_aliases}}{$key};
        my $subname = "IkiWiki::PageSpec::match_$key";

        error(gettext("PageSpec already defined for alias ")."'$key'")
            if ref *$subname{CODE};

        my $entered;
        *{ $subname } = sub {
          my $path = shift;
          error(gettext("PageSpec alias defined recursively: ")."'$key'") if $entered;
          $entered = 1;
          my $result = IkiWiki::pagespec_match($path, $value);
          $entered = 0;
          return $result;
        }
    }
}

1;
