Filename | /usr/local/src/github.com/foswiki/core/lib/Foswiki/Render/Anchors.pm |
Statements | Executed 237 statements in 2.90ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
7 | 2 | 1 | 686µs | 1.14ms | make | Foswiki::Render::Anchors::
92 | 15 | 1 | 268µs | 268µs | CORE:subst (opcode) | Foswiki::Render::Anchors::
6 | 1 | 1 | 207µs | 2.20ms | makeHTMLTarget | Foswiki::Render::Anchors::
6 | 1 | 1 | 146µs | 146µs | addUnique | Foswiki::Render::Anchors::
20 | 3 | 1 | 103µs | 103µs | CORE:regcomp (opcode) | Foswiki::Render::Anchors::
5 | 1 | 1 | 39µs | 39µs | clear | Foswiki::Render::Anchors::
14 | 1 | 1 | 33µs | 33µs | CORE:substcont (opcode) | Foswiki::Render::Anchors::
13 | 2 | 1 | 27µs | 27µs | CORE:match (opcode) | Foswiki::Render::Anchors::
1 | 1 | 1 | 25µs | 33µs | BEGIN@16 | Foswiki::Render::Anchors::
1 | 1 | 1 | 23µs | 23µs | new | Foswiki::Render::Anchors::
1 | 1 | 1 | 23µs | 149µs | add | Foswiki::Render::Anchors::
1 | 1 | 1 | 17µs | 34µs | BEGIN@17 | Foswiki::Render::Anchors::
1 | 1 | 1 | 16µs | 63µs | BEGIN@18 | Foswiki::Render::Anchors::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | # See bottom of file for license and copyright information | ||||
2 | |||||
3 | =begin TML | ||||
4 | |||||
5 | ---+ package Foswiki::Render::Anchors | ||||
6 | |||||
7 | Support for rendering anchors. Objects of this class represent | ||||
8 | a set of generated anchor names, which must be unique in a rendering | ||||
9 | context (topic). The renderer maintains a set of these objects, one | ||||
10 | for each topic, to ensure that anchor names are not re-used. | ||||
11 | |||||
12 | =cut | ||||
13 | |||||
14 | package Foswiki::Render::Anchors; | ||||
15 | |||||
16 | 2 | 48µs | 2 | 41µs | # spent 33µs (25+8) within Foswiki::Render::Anchors::BEGIN@16 which was called:
# once (25µs+8µs) by Foswiki::Render::BEGIN@19 at line 16 # spent 33µs making 1 call to Foswiki::Render::Anchors::BEGIN@16
# spent 8µs making 1 call to strict::import |
17 | 2 | 43µs | 2 | 52µs | # spent 34µs (17+18) within Foswiki::Render::Anchors::BEGIN@17 which was called:
# once (17µs+18µs) by Foswiki::Render::BEGIN@19 at line 17 # spent 34µs making 1 call to Foswiki::Render::Anchors::BEGIN@17
# spent 18µs making 1 call to warnings::import |
18 | 2 | 1.23ms | 2 | 110µs | # spent 63µs (16+47) within Foswiki::Render::Anchors::BEGIN@18 which was called:
# once (16µs+47µs) by Foswiki::Render::BEGIN@19 at line 18 # spent 63µs making 1 call to Foswiki::Render::Anchors::BEGIN@18
# spent 47µs making 1 call to Assert::import |
19 | |||||
20 | =begin TML | ||||
21 | |||||
22 | ---++ ClassMethod new() | ||||
23 | |||||
24 | Construct a new anchors set. | ||||
25 | |||||
26 | =cut | ||||
27 | |||||
28 | # spent 23µs within Foswiki::Render::Anchors::new which was called:
# once (23µs+0s) by Foswiki::Render::getAnchorNames at line 2206 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Render.pm | ||||
29 | 1 | 27µs | return bless( { names => {} }, shift ); | ||
30 | } | ||||
31 | |||||
32 | =begin TML | ||||
33 | |||||
34 | ---++ ObjectMethod clear() | ||||
35 | |||||
36 | Clear the anchor set. Clearing the anchor set will cause it to forget | ||||
37 | any anchors generated to date. | ||||
38 | |||||
39 | =cut | ||||
40 | |||||
41 | # spent 39µs within Foswiki::Render::Anchors::clear which was called 5 times, avg 8µs/call:
# 5 times (39µs+0s) by Foswiki::Render::getRenderedVersion at line 1235 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Render.pm, avg 8µs/call | ||||
42 | 5 | 8µs | my $this = shift; | ||
43 | 5 | 38µs | $this->{names} = {}; | ||
44 | } | ||||
45 | |||||
46 | =begin TML | ||||
47 | |||||
48 | ---++ ObjectMethod add($text) -> $name | ||||
49 | Add a new anchor to the set. Return the name that was added. | ||||
50 | Note that if a name is added twice, it isn't an error, but only | ||||
51 | the one name is added. | ||||
52 | |||||
53 | =cut | ||||
54 | |||||
55 | # spent 149µs (23+126) within Foswiki::Render::Anchors::add which was called:
# once (23µs+126µs) by Foswiki::Render::getRenderedVersion at line 1240 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Render.pm | ||||
56 | 1 | 4µs | my ( $this, $text ) = @_; | ||
57 | 1 | 10µs | 1 | 126µs | my $anchorName = make($text); # spent 126µs making 1 call to Foswiki::Render::Anchors::make |
58 | 1 | 3µs | $this->{names}->{$anchorName} = 1; | ||
59 | 1 | 11µs | return $anchorName; | ||
60 | } | ||||
61 | |||||
62 | =begin TML | ||||
63 | |||||
64 | ---++ ObjectMethod addUnique($text [,$alreadyMade]) -> $uniqueName | ||||
65 | Add a new anchor to the set. if it's already present, rename it. | ||||
66 | |||||
67 | If =$alreadyMade=, then $text is assumed to be a valid anchor name | ||||
68 | that was made by =make=. | ||||
69 | |||||
70 | Return the name that was added. | ||||
71 | |||||
72 | =cut | ||||
73 | |||||
74 | # spent 146µs within Foswiki::Render::Anchors::addUnique which was called 6 times, avg 24µs/call:
# 6 times (146µs+0s) by Foswiki::Render::Anchors::makeHTMLTarget at line 188, avg 24µs/call | ||||
75 | 6 | 15µs | my ( $this, $text, $alreadyMade ) = @_; | ||
76 | 6 | 8µs | my $anchorName; | ||
77 | 6 | 14µs | if ($alreadyMade) { | ||
78 | 6 | 10µs | $anchorName = $text; | ||
79 | } | ||||
80 | else { | ||||
81 | $anchorName = make($text); | ||||
82 | } | ||||
83 | 6 | 8µs | my $cnt = 1; | ||
84 | 6 | 8µs | my $suffix = ''; | ||
85 | |||||
86 | 6 | 22µs | while ( exists $this->{names}->{ $anchorName . $suffix } ) { | ||
87 | |||||
88 | # $anchorName.$suffix must _always_ be 'compatible', or things | ||||
89 | # would get complicated (whatever that means) | ||||
90 | $suffix = '_AN' . $cnt++; | ||||
91 | |||||
92 | # limit resulting name to 32 chars | ||||
93 | $anchorName = substr( $anchorName, 0, 32 - length($suffix) ); | ||||
94 | |||||
95 | # this is only needed because '__' would not be 'compatible' | ||||
96 | $anchorName =~ s/_+$//g; | ||||
97 | } | ||||
98 | 6 | 8µs | $anchorName .= $suffix; | ||
99 | 6 | 25µs | $this->{names}->{$anchorName} = 1; | ||
100 | 6 | 40µs | return $anchorName; | ||
101 | } | ||||
102 | |||||
103 | =begin TML | ||||
104 | |||||
105 | ---++ StaticMethod make( $text ) -> $name | ||||
106 | |||||
107 | Make an anchor name from some text, subject to: | ||||
108 | 1 Given the same text, this function must always return the same | ||||
109 | anchor name | ||||
110 | 2 NAME tokens must begin with a letter ([A-Za-z]) and may be | ||||
111 | followed by any number of letters, digits ([0-9]), hyphens ("-"), | ||||
112 | underscores ("_"), colons (":"), and periods ("."). | ||||
113 | (from http://www.w3.org/TR/html401/struct/links.html#h-12.2.1) | ||||
114 | |||||
115 | The making process tranforms an arbitrary text string to a string that | ||||
116 | can legally be used for an HTML anchor. | ||||
117 | |||||
118 | =cut | ||||
119 | |||||
120 | sub make { | ||||
121 | 7 | 14µs | my ($text) = @_; | ||
122 | |||||
123 | 7 | 174µs | 21 | 84µs | $text =~ s/^\s*(.*?)\s*$/$1/; # spent 50µs making 7 calls to Foswiki::Render::Anchors::CORE:subst, avg 7µs/call
# spent 33µs making 14 calls to Foswiki::Render::Anchors::CORE:substcont, avg 2µs/call |
124 | 7 | 108µs | 14 | 50µs | $text =~ s/$Foswiki::regex{headerPatternNoTOC}//go; # spent 31µs making 7 calls to Foswiki::Render::Anchors::CORE:regcomp, avg 4µs/call
# spent 19µs making 7 calls to Foswiki::Render::Anchors::CORE:subst, avg 3µs/call |
125 | |||||
126 | 7 | 105µs | 14 | 48µs | if ( $text =~ /^$Foswiki::regex{anchorRegex}$/ ) { # spent 33µs making 7 calls to Foswiki::Render::Anchors::CORE:regcomp, avg 5µs/call
# spent 15µs making 7 calls to Foswiki::Render::Anchors::CORE:match, avg 2µs/call |
127 | |||||
128 | # accept, already valid -- just remove leading # | ||||
129 | 1 | 12µs | return substr( $text, 1 ); | ||
130 | } | ||||
131 | |||||
132 | # $anchorName is a *byte* string. If it contains any wide characters | ||||
133 | # the encoding algorithm will not work. | ||||
134 | #ASSERT($text !~ /[^\x00-\xFF]/) if DEBUG; | ||||
135 | 6 | 40µs | 6 | 14µs | $text =~ s/[^\x00-\xFF]//g; # spent 14µs making 6 calls to Foswiki::Render::Anchors::CORE:subst, avg 2µs/call |
136 | 6 | 32µs | 6 | 26µs | ASSERT( $text !~ /[^\x00-\xFF]/ ) if DEBUG; # spent 26µs making 6 calls to Assert::ASSERTS_OFF, avg 4µs/call |
137 | |||||
138 | # SMELL: This corrects for anchors containing < and > | ||||
139 | # which for some reason are encoded when building the anchor, but | ||||
140 | # un-encoded when building the link. | ||||
141 | # | ||||
142 | # Convert &, < and > back from entity | ||||
143 | 6 | 41µs | 6 | 15µs | $text =~ s/</</g; # spent 15µs making 6 calls to Foswiki::Render::Anchors::CORE:subst, avg 2µs/call |
144 | 6 | 33µs | 6 | 9µs | $text =~ s/>/>/g; # spent 9µs making 6 calls to Foswiki::Render::Anchors::CORE:subst, avg 1µs/call |
145 | 6 | 32µs | 6 | 8µs | $text =~ s/&/&/g; # spent 8µs making 6 calls to Foswiki::Render::Anchors::CORE:subst, avg 1µs/call |
146 | |||||
147 | # strip out potential links so they don't get rendered. | ||||
148 | # remove double bracket link | ||||
149 | 6 | 34µs | 6 | 11µs | $text =~ s/\[(?:\[.*?\])?\[(.*?)\]\s*\]/$1/g; # spent 11µs making 6 calls to Foswiki::Render::Anchors::CORE:subst, avg 2µs/call |
150 | |||||
151 | # remove HTML tags and entities | ||||
152 | 6 | 42µs | 6 | 18µs | $text =~ s/<\/?[a-zA-Z][^>]*>//gi; # spent 18µs making 6 calls to Foswiki::Render::Anchors::CORE:subst, avg 3µs/call |
153 | 6 | 33µs | 6 | 9µs | $text =~ s/&#?[a-zA-Z0-9]+;//g; # spent 9µs making 6 calls to Foswiki::Render::Anchors::CORE:subst, avg 1µs/call |
154 | |||||
155 | # remove escape from escaped wikiWords | ||||
156 | 6 | 96µs | 12 | 49µs | $text =~ # spent 39µs making 6 calls to Foswiki::Render::Anchors::CORE:regcomp, avg 6µs/call
# spent 10µs making 6 calls to Foswiki::Render::Anchors::CORE:subst, avg 2µs/call |
157 | s/!($Foswiki::regex{wikiWordRegex}|$Foswiki::regex{abbrevRegex})/$1/go; | ||||
158 | |||||
159 | # remove spaces | ||||
160 | 6 | 57µs | 6 | 29µs | $text =~ s/\s+/_/g; # spent 29µs making 6 calls to Foswiki::Render::Anchors::CORE:subst, avg 5µs/call |
161 | |||||
162 | # use _ as an escape character to escape any byte outside the | ||||
163 | # range specified by http://www.w3.org/TR/html401/struct/links.html | ||||
164 | 6 | 37µs | 6 | 13µs | $text =~ s/([^A-Za-z0-9:._])/'_'.sprintf('%02d', ord($1))/ge; # spent 13µs making 6 calls to Foswiki::Render::Anchors::CORE:subst, avg 2µs/call |
165 | |||||
166 | # clean up a bit | ||||
167 | 6 | 33µs | 6 | 10µs | $text =~ s/__/_/g; # spent 10µs making 6 calls to Foswiki::Render::Anchors::CORE:subst, avg 2µs/call |
168 | 6 | 40µs | 6 | 15µs | $text =~ s/^_*//; # spent 15µs making 6 calls to Foswiki::Render::Anchors::CORE:subst, avg 3µs/call |
169 | 6 | 66µs | 6 | 39µs | $text =~ s/_*$//; # spent 39µs making 6 calls to Foswiki::Render::Anchors::CORE:subst, avg 6µs/call |
170 | |||||
171 | # Ensure the anchor always starts with an [A-Za-z] | ||||
172 | 6 | 38µs | 6 | 12µs | $text = 'A_' . $text unless $text =~ /^[A-Za-z]/; # spent 12µs making 6 calls to Foswiki::Render::Anchors::CORE:match, avg 2µs/call |
173 | |||||
174 | 6 | 65µs | return $text; | ||
175 | } | ||||
176 | |||||
177 | =begin TML | ||||
178 | |||||
179 | ---++ ObjectMethod makeHTMLTarget($name) -> $html | ||||
180 | Make an HTML anchor that can be used as the target of links. | ||||
181 | |||||
182 | =cut | ||||
183 | |||||
184 | # spent 2.20ms (207µs+1.99) within Foswiki::Render::Anchors::makeHTMLTarget which was called 6 times, avg 366µs/call:
# 6 times (207µs+1.99ms) by Foswiki::Render::_makeAnchorHeading at line 452 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Render.pm, avg 366µs/call | ||||
185 | 6 | 14µs | my ( $this, $text ) = @_; | ||
186 | |||||
187 | 6 | 35µs | 6 | 1.02ms | my $goodAnchor = make($text); # spent 1.02ms making 6 calls to Foswiki::Render::Anchors::make, avg 170µs/call |
188 | 6 | 87µs | 12 | 973µs | my $html = CGI::a( { name => $this->addUnique( $goodAnchor, 1 ) }, '' ); # spent 827µs making 6 calls to CGI::a, avg 138µs/call
# spent 146µs making 6 calls to Foswiki::Render::Anchors::addUnique, avg 24µs/call |
189 | |||||
190 | 6 | 11µs | if ( $Foswiki::cfg{RequireCompatibleAnchors} ) { | ||
191 | |||||
192 | # Add in extra anchors compatible with old formats, as required | ||||
193 | require Foswiki::Compatibility; | ||||
194 | my @extras = Foswiki::Compatibility::makeCompatibleAnchors($text); | ||||
195 | foreach my $extra (@extras) { | ||||
196 | next if ( $extra eq $goodAnchor ); | ||||
197 | $html .= CGI::a( { name => $this->addUnique( $extra, 1 ), }, '' ); | ||||
198 | } | ||||
199 | } | ||||
200 | 6 | 38µs | return $html; | ||
201 | } | ||||
202 | |||||
203 | 1 | 4µs | 1; | ||
204 | __END__ | ||||
sub Foswiki::Render::Anchors::CORE:match; # opcode | |||||
# spent 103µs within Foswiki::Render::Anchors::CORE:regcomp which was called 20 times, avg 5µs/call:
# 7 times (33µs+0s) by Foswiki::Render::Anchors::make at line 126, avg 5µs/call
# 7 times (31µs+0s) by Foswiki::Render::Anchors::make at line 124, avg 4µs/call
# 6 times (39µs+0s) by Foswiki::Render::Anchors::make at line 156, avg 6µs/call | |||||
# spent 268µs within Foswiki::Render::Anchors::CORE:subst which was called 92 times, avg 3µs/call:
# 7 times (50µs+0s) by Foswiki::Render::Anchors::make at line 123, avg 7µs/call
# 7 times (19µs+0s) by Foswiki::Render::Anchors::make at line 124, avg 3µs/call
# 6 times (39µs+0s) by Foswiki::Render::Anchors::make at line 169, avg 6µs/call
# 6 times (29µs+0s) by Foswiki::Render::Anchors::make at line 160, avg 5µs/call
# 6 times (18µs+0s) by Foswiki::Render::Anchors::make at line 152, avg 3µs/call
# 6 times (15µs+0s) by Foswiki::Render::Anchors::make at line 168, avg 3µs/call
# 6 times (15µs+0s) by Foswiki::Render::Anchors::make at line 143, avg 2µs/call
# 6 times (14µs+0s) by Foswiki::Render::Anchors::make at line 135, avg 2µs/call
# 6 times (13µs+0s) by Foswiki::Render::Anchors::make at line 164, avg 2µs/call
# 6 times (11µs+0s) by Foswiki::Render::Anchors::make at line 149, avg 2µs/call
# 6 times (10µs+0s) by Foswiki::Render::Anchors::make at line 156, avg 2µs/call
# 6 times (10µs+0s) by Foswiki::Render::Anchors::make at line 167, avg 2µs/call
# 6 times (9µs+0s) by Foswiki::Render::Anchors::make at line 153, avg 1µs/call
# 6 times (9µs+0s) by Foswiki::Render::Anchors::make at line 144, avg 1µs/call
# 6 times (8µs+0s) by Foswiki::Render::Anchors::make at line 145, avg 1µs/call | |||||
# spent 33µs within Foswiki::Render::Anchors::CORE:substcont which was called 14 times, avg 2µs/call:
# 14 times (33µs+0s) by Foswiki::Render::Anchors::make at line 123, avg 2µs/call |