~ubuntu-branches/ubuntu/gutsy/horae/gutsy

« back to all changes in this revision

Viewing changes to 0CPAN/Tk-Pod-0.9932/Pod/SimpleBridge.pm

  • Committer: Bazaar Package Importer
  • Author(s): Carlo Segre
  • Date: 2006-12-28 12:36:48 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20061228123648-9xnjr76wfthd92cq
Tags: 064-1
New upstream release, dropped dependency on libtk-filedialog-perl.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
 
2
 
require 5;
3
 
use strict;
4
 
package Tk::Pod::SimpleBridge;
5
 
# Interface between Tk::Pod and Pod::Simple
6
 
 
7
 
use vars qw($VERSION);
8
 
$VERSION = sprintf("%d.%02d", q$Revision: 5.1 $ =~ /(\d+)\.(\d+)/);
9
 
 
10
 
BEGIN {  # Make a DEBUG constant very first thing...
11
 
  if(defined &DEBUG) {
12
 
  } elsif(($ENV{'TKPODDEBUG'} || '') =~ m/^(\d+)/) { # untaint
13
 
    my $debug = $1;
14
 
    *DEBUG = sub () { $debug };
15
 
  } else {
16
 
    *DEBUG = sub () {0};
17
 
  }
18
 
}
19
 
 
20
 
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
21
 
 
22
 
use Pod::Simple::PullParser;
23
 
use Tk::Pod::Styles;
24
 
use vars qw(@ISA);
25
 
@ISA = qw(Tk::Pod::Styles);
26
 
 
27
 
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
28
 
sub no_op {return}
29
 
 
30
 
sub process { # main routine: non-handler
31
 
  my ($w,$file_or_textref, $title) = @_;  # window, filename or string ref, title (optional)
32
 
 
33
 
  my $p = $w->{'pod_parser'} = Pod::Simple::PullParser->new;
34
 
  $p->set_source($file_or_textref);
35
 
  my $file = !ref $file_or_textref && $file_or_textref;
36
 
 
37
 
  $w->toplevel->Busy;
38
 
  $w->init_styles;
39
 
 
40
 
  my $process_no;
41
 
  $w->{ProcessNo}++;
42
 
  $process_no = $w->{ProcessNo};
43
 
 
44
 
  $w->{'sections'} = [];
45
 
  $w->{'pod_tag'} = '10000'; # counter
46
 
#XXX  my $style_stack = $w->{'style_stack'} ||= []; # || is probably harmful
47
 
  my $style_stack = $w->{'style_stack'} = [];
48
 
 
49
 
  my @pod_marks;
50
 
 
51
 
  DEBUG and $file and warn "Pull-parsing $file (process number $process_no)\n";
52
 
  $w->{'pod_title'} = $p->get_short_title || $title || $file;
53
 
 
54
 
  my($token, $tagname, $style);
55
 
  my $last_update = Tk::timeofday();
56
 
  while($token = $p->get_token) {
57
 
 
58
 
    DEBUG > 7 and warn " t:", $token->dump, "\n";
59
 
 
60
 
    if($token->is_text) {
61
 
      DEBUG > 10 and warn " ->pod_text( ", $token->text, ")\n";
62
 
      $w->pod_text( $token );
63
 
 
64
 
    } elsif($token->is_start) {
65
 
      ($tagname = $token->tagname ) =~ tr/-:./__/;
66
 
      $style    = "style_"     . $tagname;
67
 
      $tagname  = "pod_start_" . $tagname;
68
 
      DEBUG > 7 and warn " ->$tagname & ->$style\n";
69
 
      push @pod_marks, $w->index('end -1c');
70
 
       # Yes, save the start-point for every element,
71
 
       #  for feeding to its end-tag event.
72
 
 
73
 
      if( $w->can($style) ) {
74
 
        push @$style_stack,  $w->$style($token);
75
 
        DEBUG > 5 and warn "Style stack after adding ->$style: ",
76
 
         join("|", map join('.',@$_), @{ $w->{'style_stack'} } ), "\n";
77
 
      }
78
 
 
79
 
      &{ $w->can($tagname) || next }( $w, $token );
80
 
      DEBUG > 10 and warn "   back from ->$tagname\n";
81
 
 
82
 
    } elsif($token->is_end) {
83
 
      ($tagname = $token->tagname ) =~ tr/-:./__/;
84
 
      $style    = "style_"   . $tagname;
85
 
      $tagname  = "pod_end_" . $tagname;
86
 
 
87
 
      DEBUG > 7 and warn " ->$tagname & $style\n";
88
 
 
89
 
      &{ $w->can($tagname) || \&no_op }( $w, $token, pop(@pod_marks) );
90
 
       # the output of that pop() is the start-point of this element
91
 
      DEBUG > 10 and warn "   back from ->$tagname\n";
92
 
 
93
 
      if( $w->can($style) ) {
94
 
        pop @$style_stack;
95
 
        DEBUG > 5 and warn "Style stack after popping results of ->$style: ",
96
 
         join("|", map join('.',@$_), @{ $w->{'style_stack'} } ), "\n";
97
 
      }
98
 
    }
99
 
 
100
 
    if (Tk::timeofday() > $last_update+0.5) { # XXX make configurable
101
 
      $w->update;
102
 
      $last_update = Tk::timeofday();
103
 
      do { warn "ABORT!"; return } if $w->{ProcessNo} != $process_no;
104
 
    }
105
 
 
106
 
  }
107
 
 
108
 
  undef $p;
109
 
  delete $w->{'pod_parser'};
110
 
  DEBUG and $file and warn "Done rendering $file\n";
111
 
 
112
 
  $w->parent->add_section_menu if $w->parent->can('add_section_menu');
113
 
  $w->Callback('-poddone', $file);
114
 
  # set (invisible) insertion cursor to top of file
115
 
  $w->markSet(insert => '@0,0');
116
 
  $w->toplevel->Unbusy;
117
 
}
118
 
 
119
 
###########################################################################
120
 
 
121
 
sub pod_text {
122
 
  my($w, $t) = @_;
123
 
  if( $w->{'pod_in_X'} ) {
124
 
    # no-op
125
 
  } else {
126
 
    # Emit it with whatever styles are in effect.
127
 
 
128
 
    my %attributes = (map @$_, @{ $w->{'style_stack'} } );
129
 
    DEBUG > 4 and warn "Inserting <", $t->text, "> with attributes: ",
130
 
      join('/', %attributes), "\n";
131
 
 
132
 
    my $startpoint = $w->index('end -1c');
133
 
    $w->insert( 'end -1c', $t->text );
134
 
    
135
 
    $w->tag(
136
 
      'add',
137
 
      $w->tag_for(\%attributes),
138
 
      $startpoint => 'end -1c'
139
 
    );
140
 
  }
141
 
  return;
142
 
}
143
 
 
144
 
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
145
 
 
146
 
sub pod_start_Document {
147
 
  $_[0]->toplevel->title( "Tkpod: " . $_[0]->{'pod_title'} . " (loading)");
148
 
  $_[0]->toplevel->update;
149
 
  # XXX  Is it bad form to manipulate the top level?
150
 
  return;
151
 
}
152
 
 
153
 
sub pod_end_Document {
154
 
  $_[0]->toplevel->title( "Tkpod: " . $_[0]->{'pod_title'});
155
 
  $_[0]->toplevel->update;
156
 
  # XXX  Is it bad form to manipulate the top level?
157
 
  return;
158
 
}
159
 
 
160
 
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
161
 
 
162
 
sub nlnl { $_[0]->insert( 'end -1c', "\n\n" ); $_[0]; }
163
 
sub nl { $_[0]->insert( 'end -1c', "\n" ); $_[0]; }
164
 
 
165
 
sub fake_unget_bold_text {
166
 
  require Pod::Simple::PullParserStartToken;
167
 
  require Pod::Simple::PullParserTextToken;
168
 
  require Pod::Simple::PullParserEndToken;
169
 
 
170
 
  $_[0]{'pod_parser'}->unget_token(
171
 
    Pod::Simple::PullParserStartToken->new('B'),
172
 
    Pod::Simple::PullParserTextToken->new($_[1]),
173
 
    Pod::Simple::PullParserEndToken->new('B'),
174
 
  );
175
 
}
176
 
 
177
 
sub pod_start_item_bullet {
178
 
  $_[0]->fake_unget_bold_text('* ');
179
 
}
180
 
sub pod_start_item_number {
181
 
  $_[0]->fake_unget_bold_text($_[1]->attr('number') . '. ');
182
 
}
183
 
 
184
 
sub pod_end_Para        { $_[0]->_indent($_[2]); $_[0]->nlnl }
185
 
sub pod_end_Verbatim    { $_[0]->_indent($_[2]); $_[0]->nlnl }
186
 
sub pod_end_item_bullet { $_[0]->_indent($_[2]); $_[0]->nlnl }
187
 
sub pod_end_item_number { $_[0]->_indent($_[2]); $_[0]->nlnl }
188
 
sub pod_end_item_text   { $_[0]->_indent($_[2]); $_[0]->nl }
189
 
 
190
 
sub pod_end_over_text   { $_[0]->nl } # XXX ok?
191
 
 
192
 
sub _indent {
193
 
  my ($w, $start) = @_;
194
 
 
195
 
  my $indent = 0;
196
 
  foreach my $s (@{ $w->{'style_stack'} }) {
197
 
    $indent += $s->[1] if @$s and $s->[0] eq 'indent';
198
 
     # yes, indent is special -- it always has to be first
199
 
  }
200
 
  $indent = 0 if $indent < 0;
201
 
  
202
 
  DEBUG > 5 and warn "Style stack giving indent of $indent for $start: ",
203
 
         join("|", map join('.',@$_), @{ $w->{'style_stack'} } ), "\n";
204
 
  
205
 
  my $tag = "Indent" . ($indent+0);
206
 
  unless (exists $w->{'pod_indent_tag_known'}{$tag}) {
207
 
    $w->{'pod_indent_tag_known'}{$tag} = 1;
208
 
    
209
 
    $indent *= 8;  # XXX  Why 8?
210
 
    
211
 
    $w->tag('configure' => $tag,
212
 
            '-lmargin2' => $indent . 'p',
213
 
            '-rmargin'  => $indent . 'p',
214
 
            '-lmargin1' => $indent . 'p'
215
 
           );
216
 
  }
217
 
  $w->tag('add', $tag, $start, 'end -1c');
218
 
  DEBUG > 3 and warn "Applying $tag to $start\n";
219
 
  return;
220
 
}
221
 
 
222
 
 
223
 
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
224
 
# All we need for X<...>, I think:
225
 
sub pod_start_X { $_[0]{'pod_in_X'}++; return; }
226
 
sub pod_end_X   { $_[0]{'pod_in_X'}--; return; }
227
 
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
228
 
 
229
 
sub tag_for {
230
 
  my($w, $attr) = @_;
231
 
  my $canonical_form =
232
 
    join( '~', map {; $_, $attr->{$_}}
233
 
      sort
234
 
        grep $_ ne 'indent',
235
 
          keys %$attr
236
 
  ) || 'nihil';
237
 
  
238
 
  return
239
 
    $w->{'known_tags'}{$canonical_form} ||=
240
 
    do {
241
 
      # initialize and return a new tagname
242
 
      DEBUG and warn "Making a tag for $canonical_form\n";
243
 
      $attr->{'family'}  = 'times'  unless exists $attr->{'family'};
244
 
      $attr->{'weight'}  = 'medium' unless exists $attr->{'weight'};
245
 
      $attr->{'slant'}   = 'r'      unless exists $attr->{'slant'};
246
 
      $attr->{'size'}    = 10       unless exists $attr->{'size'};
247
 
      $attr->{'spacing'} = '*'      unless exists $attr->{'spacing'};
248
 
      $attr->{'slant'}   = substr( $attr->{'slant'},0,1 );
249
 
      
250
 
      my $font_name = join ' ',
251
 
        $attr->{'family'},
252
 
        $attr->{'size'},
253
 
        ($attr->{'weight'} ne 'medium') ? 'bold'   : (),
254
 
        ($attr->{'slant'}  ne 'r'     ) ? 'italic' : (),
255
 
      ;
256
 
      
257
 
      DEBUG and warn "Defining new tag $canonical_form with font $font_name\n";
258
 
      
259
 
      $w->tagConfigure(
260
 
        $canonical_form,
261
 
        '-font' => $font_name,
262
 
        ('none' eq ($attr->{'wrap'} || '')) ? ('-wrap' => 'none') : (),
263
 
        $attr->{'underline'} ? ('-underline' => 'true') : (),
264
 
      );
265
 
      DEBUG > 10 and sleep 1;
266
 
      $canonical_form;
267
 
    }
268
 
  ;
269
 
}
270
 
 
271
 
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
272
 
 
273
 
sub pod_start_L {
274
 
  push @{ $_[0]->{'pod_L_attr_stack'} }, $_[1]->attr_hash;
275
 
}
276
 
 
277
 
sub pod_end_L   {
278
 
  my $w = $_[0];
279
 
  my $attr = pop @{ $w->{'pod_L_attr_stack'} };
280
 
 
281
 
  #$w->tag('add', 'L' , $_[2], 'end -1c');
282
 
  
283
 
  my $tag = # make a unique identifier for this guy:
284
 
    join "__", '!',
285
 
      map defined($_) ? $_ : '',
286
 
        @$attr{'type', 'to', 'section'};
287
 
    #"!" . $attr->{'to'}
288
 
  ;
289
 
  $tag =~ tr/ /_/;
290
 
  DEBUG > 2 and warn "Link-tag <$tag>\n";
291
 
  
292
 
  my $to      = $attr->{'to'}     ; # might be undef!
293
 
  my $section = $attr->{'section'}; # might be undef!
294
 
  
295
 
  my $methodname;
296
 
  if($attr->{'type'} eq 'pod')      {
297
 
    #$methodname = defined($to) ? 'Link' : 'Link_my_section';
298
 
    $methodname = 'Link';
299
 
  } elsif($attr->{'type'} eq 'url') {
300
 
    $methodname = 'Link_url'
301
 
  } elsif($attr->{'type'} eq 'man') {
302
 
    $methodname = 'Link_man'
303
 
  } else {
304
 
    DEBUG and warn "Unknown link-type $$attr{'type'}!\n";
305
 
  }
306
 
 
307
 
  $section = '' . $section if defined $section and ref $section;
308
 
 
309
 
  if(!defined $methodname) {
310
 
    DEBUG > 2 and warn "No method for $$attr{'type'} links.\n";
311
 
  } elsif($w->can($methodname)) {
312
 
    DEBUG > 2 and warn "Binding $tag to $methodname\n";
313
 
    $w->tag('bind', $tag, '<ButtonRelease-1>',
314
 
            [$w, $methodname, 'reuse', Tk::Ev('@%x,%y'), $to, $section]);
315
 
    $w->tag('bind', $tag, '<Shift-ButtonRelease-1>',
316
 
            [$w, $methodname, 'new',   Tk::Ev('@%x,%y'), $to, $section]);
317
 
    $w->tag('bind', $tag, '<ButtonRelease-2>',
318
 
            [$w, $methodname, 'new',   Tk::Ev('@%x,%y'), $to, $section]);
319
 
    $w->tag('bind', $tag, '<Enter>' => [$w, 'EnterLink']);
320
 
    $w->tag('bind', $tag, '<Leave>' => [$w, 'LeaveLink']);
321
 
    $w->tag('configure', $tag, '-underline' => 1, '-foreground' => 'blue' );
322
 
  } else {
323
 
    DEBUG > 2 and warn "Can't bind $tag to $methodname\n";
324
 
    # green for no-good
325
 
    $w->tag('configure', $tag, '-underline' => 1, '-foreground' => 'darkgreen' );
326
 
  }
327
 
  $w->tag('add', $tag, $_[2] ,'end -1c');
328
 
 
329
 
  return;
330
 
}
331
 
 
332
 
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
333
 
 
334
 
sub pod_start_head1 { $_[0]->_common_heading('head1'); }
335
 
sub pod_start_head2 { $_[0]->_common_heading('head2'); }
336
 
sub pod_start_head3 { $_[0]->_common_heading('head3'); }
337
 
sub pod_start_head4 { $_[0]->_common_heading('head4'); }
338
 
 
339
 
sub pod_end_head1 {  $_[0]->nlnl }
340
 
sub pod_end_head2 {  $_[0]->nlnl }
341
 
sub pod_end_head3 {  $_[0]->nlnl }
342
 
sub pod_end_head4 {  $_[0]->nlnl }
343
 
 
344
 
sub _common_heading {
345
 
  my $w = $_[0];
346
 
  my $p = $w->{'pod_parser'};
347
 
  my $end_tag = $_[1];
348
 
  
349
 
  my @to_put_back;
350
 
  my $text = '';
351
 
  my $token;
352
 
  my $in_X = 0;
353
 
  while($token = $p->get_token) {
354
 
    push @to_put_back, $token;
355
 
    if( $token->is_end ) {
356
 
      last if $token->is_tag($end_tag);
357
 
      --$in_X if $token->is_tag('X');
358
 
    } elsif($token->is_start) {
359
 
      ++$in_X if $token->is_tag('X');
360
 
    } elsif($token->is_text) {
361
 
      $text .= $token->text unless $in_X;
362
 
    }
363
 
    last if @to_put_back > 40; # too complex a heading!
364
 
  }
365
 
 
366
 
  if(length $text) {
367
 
    my $level;
368
 
    $end_tag =~ m/(\d+)$/ or die "WHAAAT?  $end_tag!?";
369
 
    $level = $1;
370
 
    push @{$w->{'sections'}}, [$level, $text, $w->index('end')];
371
 
    DEBUG and warn "Noting section heading head$level \"$text\".\n";
372
 
  }
373
 
 
374
 
  $p->unget_token(@to_put_back);
375
 
  return;
376
 
}
377
 
 
378
 
# ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
379
 
 
380
 
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
381
 
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
382
 
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
383
 
1;
384
 
__END__
385
 
 
386
 
=head1 NAME
387
 
 
388
 
Tk::Pod::SimpleBridge -- render Pod::Simple events to a Tk::Pod window
389
 
 
390
 
=head1 SYNOPSIS
391
 
 
392
 
  [
393
 
    This is a class internal to Tk::Pod.
394
 
    No user-serviceable parts inside.
395
 
  ]
396
 
 
397
 
=head1 DESCRIPTION
398
 
 
399
 
This class contains methods that Tk::Pod (specifically Tk::Pod::Text)
400
 
uses to render a pod page's text into its window.  It uses L<Pod::Simple>
401
 
(specifically L<Pod::Simple::PullParser>) to do the parsing.
402
 
 
403
 
Tk::Pod used to use Tk::Parse (a snapshot of an old old Pod-parser)
404
 
to do the Pod-parsing.  But it doesn't anymore -- it now uses Pod::Simple
405
 
via this module.
406
 
 
407
 
=head1 COPYRIGHT AND DISCLAIMERS
408
 
 
409
 
Copyright (c) 2002 Sean M. Burke.  All rights reserved.
410
 
 
411
 
This library is free software; you can redistribute it and/or modify it
412
 
under the same terms as Perl itself.
413
 
 
414
 
This program is distributed in the hope that it will be useful, but
415
 
without any warranty; without even the implied warranty of
416
 
merchantability or fitness for a particular purpose.
417
 
 
418
 
=head1 AUTHOR
419
 
 
420
 
Sean M. Burke <F<sburke@cpan.org>>, with bits of Tk code cribbed from
421
 
the old Tk::Pod::Text code that Nick Ing-Simmons
422
 
<F<nick@ni-s.u-net.com>> originally wrote.
423
 
 
424
 
Current maintainer is Slaven Rezic <F<slaven@rezic.de>>.
425
 
 
426
 
=cut