Hi,

I posted earlier asking about this ( http://www.template-toolkit.org/pipermail/templates/2005-September/007831.html ), so far with no replies.  I have done some more investigation since then and I'm reasonably sure Template Toolkit doesn't make the information I'm looking for available.  

I would like to know if I am correct about this, and also what it would take to change it.

To recap, I'm wondering if there is any way that a macro (or perhaps a PROCESS call) can know the line position it was called from.  My client wants to be able to do this:

    SELECT  [% macro_for_select_columns %]
      FROM [% macro_returning_tables %]
     WHERE [% macro_for_where_columns %]

The "macro_for_select_columns" needs to expand like this:

    SELECT  @name          = name,
            @whatever      = whatever,
            @whatever_else = whatever_else


Note that the @ signs have to line up, so the first line (@name = name) needs to be (in the macro) flush left, but subsequent lines need to pad by (in this case) 12 spaces)

What I have done so far is to create a filter that figures out the spacing, like this:


     SELECT  [% FILTER $AlignVisually %]
             [% assigned_non_primaries_comma -%][% END %]
       from [% tables %]
      where [% FILTER $AlignVisually  prepend=>'and ' %]
            [% primary_keys_anded_assigned_to %][% END %]

Inside the filter I (remove and) examine the first line to see "where" the text starts.  This requires either that the first character of the 'assigned_non_primaries_comma' be non-whitespace, or I could in special circumstances put a predefined mark in front of the assigned_non... macro call that AlignVisually would look for.

I like this solution, but my client doesn't.  He is convinced that somewhere in some corner of the module that I just haven't noticed yet there is a variable I could examine to see where on the current line a macro call was made. 

I have looked through things in a fair amount of detail.  I turned Template::Parser::DEBUG on and saw that I couldn't merely examine the "$output" variable in the block (e.g. in a RAWPERL block in the macro) because it is hidden with a my() at the beginning of the block.  I also looked through Template::Parser to see if anything jumped out at me (nothing did). 

Looking at Template::Parser::DEBUG output I noticed that there are helpful comments inserted letting you know when a FILTER block or a macro call is about to start:

for this template:

[% FILTER indent( 3 ) %]
foo
bar
baz
[% END %]

[% MACRO test_macro BLOCK %]
here is the start of test_macro


here is the end of test_macro
[% END %]

[% test_macro %]

the parser debug output looks like this:

~/work/cowan/db2/stp:$ cat stderr
[Template::Parser] compiled main template document block:
sub {
    my $context = shift || die "template sub called without context\n";
    my $stash   = $context->stash;
    my $output  = '';
    my $error;
   
    eval { BLOCK: {
#line 5 "input file handle"
       
        # FILTER
        $output .=  do {
            my $output = '';
            my $filter = $context->filter('indent', [ 3 ])
                      || $context->throw($context->error);
       
            $output .=  "\nfoo\nbar\nbaz\n";
           
            &$filter($output);
        };
       
        $output .=  "\n\n";
#line 12 "input file handle"
       
        # MACRO
        $stash->set('test_macro', sub {
            my $params = $_[0] if ref($_[0]) eq 'HASH';
            my $output = '';
       
            my $stash = $context->localise($params);
            eval {
                $output .=  "\nhere is the start of test_macro\n\n\nhere is the end of test_macro\n";
            };
            $stash = $context->delocalise();
            die $@ if $@;
            return $output;
        });
       
        $output .=  "\n\n";
#line 14 "input file handle"
        $output .=  $stash->get('test_macro');
        $output .=  "\n\n";
    } };
    if ($@) {
        $error = $context->catch($@, \$output);
        die $error unless $error->type eq 'return';
    }

    return $output;
}


I looked at the parser and I thought I saw where that debugging output was generated (but it was my first time looking at the parser, so who knows :).  It seems that it would not be too hard (famous last words) to either (a) put the current value of "$output" into the stash (under some other name of course) that a plugin/filter/macro could look at (the plugin/filter/macro could just see how many characters there are after the last newline to determine the line position) or (b) set the line position in the stash (or in a special variable like 'pos' or 'line_pos' or whatever)) or (c) both.

So, my basic questions are:

Am I right in thinking that TT does not currently give me easy access to this information?

and

How hard would it be for me to subclass Parser or modify the grammar or whatever to make it do what I want (or is there a better approach)?

Thanks!

mike

Reply via email to