Filename | /usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm |
Statements | Executed 4113 statements in 37.6ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
22 | 1 | 1 | 9.99ms | 19.2ms | formatResult | Foswiki::Search::
2 | 2 | 2 | 6.53ms | 1.68s | formatResults | Foswiki::Search::
462 | 3 | 1 | 4.32ms | 4.32ms | CORE:regcomp (opcode) | Foswiki::Search::
1 | 1 | 1 | 3.91ms | 5.43ms | BEGIN@19 | Foswiki::Search::
1 | 1 | 1 | 2.12ms | 2.42ms | BEGIN@25 | Foswiki::Search::
1 | 1 | 1 | 1.71ms | 1.88ms | BEGIN@20 | Foswiki::Search::
867 | 29 | 1 | 1.53ms | 1.53ms | CORE:subst (opcode) | Foswiki::Search::
1 | 1 | 1 | 1.35ms | 1.48ms | BEGIN@23 | Foswiki::Search::
145 | 7 | 5 | 1.23ms | 1.25ms | metacache | Foswiki::Search::
44 | 3 | 1 | 949µs | 1.50ms | __ANON__[:1327] | Foswiki::Search::
1 | 1 | 1 | 628µs | 1.03ms | BEGIN@24 | Foswiki::Search::
1 | 1 | 1 | 547µs | 3.36s | searchWeb | Foswiki::Search::
1 | 1 | 1 | 401µs | 478µs | BEGIN@26 | Foswiki::Search::
22 | 1 | 1 | 303µs | 466µs | __ANON__[:1000] | Foswiki::Search::
1 | 1 | 1 | 242µs | 10.2ms | loadTemplates | Foswiki::Search::
1 | 1 | 1 | 129µs | 628µs | finish | Foswiki::Search::
44 | 1 | 1 | 107µs | 107µs | CORE:substcont (opcode) | Foswiki::Search::
22 | 1 | 1 | 95µs | 95µs | __ANON__[:967] | Foswiki::Search::
3 | 2 | 1 | 89µs | 89µs | setup_callback | Foswiki::Search::
1 | 1 | 1 | 87µs | 4.02ms | parseSearch | Foswiki::Search::
22 | 1 | 1 | 83µs | 83µs | __ANON__[:969] | Foswiki::Search::
22 | 1 | 1 | 81µs | 81µs | __ANON__[:968] | Foswiki::Search::
22 | 1 | 1 | 80µs | 80µs | __ANON__[:970] | Foswiki::Search::
22 | 1 | 1 | 79µs | 79µs | __ANON__[:971] | Foswiki::Search::
22 | 1 | 1 | 77µs | 77µs | __ANON__[:972] | Foswiki::Search::
22 | 1 | 1 | 74µs | 74µs | __ANON__[:974] | Foswiki::Search::
22 | 1 | 1 | 74µs | 74µs | __ANON__[:973] | Foswiki::Search::
22 | 1 | 1 | 73µs | 73µs | __ANON__[:975] | Foswiki::Search::
24 | 2 | 1 | 57µs | 57µs | CORE:match (opcode) | Foswiki::Search::
1 | 1 | 1 | 26µs | 415µs | BEGIN@15 | Foswiki::Search::
1 | 1 | 1 | 25µs | 33µs | BEGIN@12 | Foswiki::Search::
1 | 1 | 1 | 22µs | 22µs | new | Foswiki::Search::
1 | 1 | 1 | 21µs | 1.73ms | __ANON__[:137] | Foswiki::Search::
1 | 1 | 1 | 20µs | 64µs | BEGIN@14 | Foswiki::Search::
1 | 1 | 1 | 20µs | 127µs | BEGIN@28 | Foswiki::Search::
1 | 1 | 1 | 17µs | 38µs | BEGIN@13 | Foswiki::Search::
1 | 1 | 1 | 16µs | 16µs | formatCommon | Foswiki::Search::
1 | 1 | 1 | 10µs | 10µs | BEGIN@17 | Foswiki::Search::
1 | 1 | 1 | 10µs | 10µs | BEGIN@21 | Foswiki::Search::
1 | 1 | 1 | 10µs | 10µs | BEGIN@30 | Foswiki::Search::
1 | 1 | 1 | 9µs | 9µs | BEGIN@18 | Foswiki::Search::
1 | 1 | 1 | 9µs | 9µs | BEGIN@22 | Foswiki::Search::
0 | 0 | 0 | 0s | 0s | __ANON__[:142] | Foswiki::Search::
0 | 0 | 0 | 0s | 0s | __ANON__[:181] | Foswiki::Search::
0 | 0 | 0 | 0s | 0s | __ANON__[:184] | Foswiki::Search::
0 | 0 | 0 | 0s | 0s | __ANON__[:650] | Foswiki::Search::
0 | 0 | 0 | 0s | 0s | __ANON__[:651] | Foswiki::Search::
0 | 0 | 0 | 0s | 0s | __ANON__[:652] | Foswiki::Search::
0 | 0 | 0 | 0s | 0s | __ANON__[:653] | Foswiki::Search::
0 | 0 | 0 | 0s | 0s | __ANON__[:654] | Foswiki::Search::
0 | 0 | 0 | 0s | 0s | __ANON__[:655] | Foswiki::Search::
0 | 0 | 0 | 0s | 0s | __ANON__[:656] | Foswiki::Search::
0 | 0 | 0 | 0s | 0s | __ANON__[:657] | Foswiki::Search::
0 | 0 | 0 | 0s | 0s | __ANON__[:663] | Foswiki::Search::
0 | 0 | 0 | 0s | 0s | __ANON__[:667] | Foswiki::Search::
0 | 0 | 0 | 0s | 0s | __ANON__[:673] | Foswiki::Search::
0 | 0 | 0 | 0s | 0s | __ANON__[:915] | Foswiki::Search::
0 | 0 | 0 | 0s | 0s | __ANON__[:922] | Foswiki::Search::
0 | 0 | 0 | 0s | 0s | __ANON__[:960] | Foswiki::Search::
0 | 0 | 0 | 0s | 0s | __ANON__[:961] | Foswiki::Search::
0 | 0 | 0 | 0s | 0s | __ANON__[:962] | Foswiki::Search::
0 | 0 | 0 | 0s | 0s | __ANON__[:963] | Foswiki::Search::
0 | 0 | 0 | 0s | 0s | __ANON__[:991] | Foswiki::Search::
0 | 0 | 0 | 0s | 0s | _collate_to_list | Foswiki::Search::
0 | 0 | 0 | 0s | 0s | _countPattern | Foswiki::Search::
0 | 0 | 0 | 0s | 0s | _extractPattern | Foswiki::Search::
0 | 0 | 0 | 0s | 0s | _isSetTrue | Foswiki::Search::
0 | 0 | 0 | 0s | 0s | displayFormField | Foswiki::Search::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | # See bottom of file for license and copyright information | ||||
2 | package Foswiki::Search; | ||||
3 | |||||
4 | =begin TML | ||||
5 | |||||
6 | ---+ package Foswiki::Search | ||||
7 | |||||
8 | This module implements all the search functionality. | ||||
9 | |||||
10 | =cut | ||||
11 | |||||
12 | 2 | 48µs | 2 | 41µs | # spent 33µs (25+8) within Foswiki::Search::BEGIN@12 which was called:
# once (25µs+8µs) by Foswiki::search at line 12 # spent 33µs making 1 call to Foswiki::Search::BEGIN@12
# spent 8µs making 1 call to strict::import |
13 | 2 | 44µs | 2 | 58µs | # spent 38µs (17+21) within Foswiki::Search::BEGIN@13 which was called:
# once (17µs+21µs) by Foswiki::search at line 13 # spent 38µs making 1 call to Foswiki::Search::BEGIN@13
# spent 21µs making 1 call to warnings::import |
14 | 2 | 50µs | 2 | 108µs | # spent 64µs (20+44) within Foswiki::Search::BEGIN@14 which was called:
# once (20µs+44µs) by Foswiki::search at line 14 # spent 64µs making 1 call to Foswiki::Search::BEGIN@14
# spent 44µs making 1 call to Assert::import |
15 | 2 | 54µs | 2 | 804µs | # spent 415µs (26+389) within Foswiki::Search::BEGIN@15 which was called:
# once (26µs+389µs) by Foswiki::search at line 15 # spent 415µs making 1 call to Foswiki::Search::BEGIN@15
# spent 389µs making 1 call to Error::import |
16 | |||||
17 | 2 | 39µs | 1 | 10µs | # spent 10µs within Foswiki::Search::BEGIN@17 which was called:
# once (10µs+0s) by Foswiki::search at line 17 # spent 10µs making 1 call to Foswiki::Search::BEGIN@17 |
18 | 2 | 38µs | 1 | 9µs | # spent 9µs within Foswiki::Search::BEGIN@18 which was called:
# once (9µs+0s) by Foswiki::search at line 18 # spent 9µs making 1 call to Foswiki::Search::BEGIN@18 |
19 | 2 | 153µs | 1 | 5.43ms | # spent 5.43ms (3.91+1.52) within Foswiki::Search::BEGIN@19 which was called:
# once (3.91ms+1.52ms) by Foswiki::search at line 19 # spent 5.43ms making 1 call to Foswiki::Search::BEGIN@19 |
20 | 2 | 184µs | 1 | 1.88ms | # spent 1.88ms (1.71+169µs) within Foswiki::Search::BEGIN@20 which was called:
# once (1.71ms+169µs) by Foswiki::search at line 20 # spent 1.88ms making 1 call to Foswiki::Search::BEGIN@20 |
21 | 2 | 38µs | 1 | 10µs | # spent 10µs within Foswiki::Search::BEGIN@21 which was called:
# once (10µs+0s) by Foswiki::search at line 21 # spent 10µs making 1 call to Foswiki::Search::BEGIN@21 |
22 | 2 | 38µs | 1 | 9µs | # spent 9µs within Foswiki::Search::BEGIN@22 which was called:
# once (9µs+0s) by Foswiki::search at line 22 # spent 9µs making 1 call to Foswiki::Search::BEGIN@22 |
23 | 2 | 156µs | 1 | 1.48ms | # spent 1.48ms (1.35+135µs) within Foswiki::Search::BEGIN@23 which was called:
# once (1.35ms+135µs) by Foswiki::search at line 23 # spent 1.48ms making 1 call to Foswiki::Search::BEGIN@23 |
24 | 2 | 132µs | 1 | 1.03ms | # spent 1.03ms (628µs+398µs) within Foswiki::Search::BEGIN@24 which was called:
# once (628µs+398µs) by Foswiki::search at line 24 # spent 1.03ms making 1 call to Foswiki::Search::BEGIN@24 |
25 | 2 | 145µs | 1 | 2.42ms | # spent 2.42ms (2.12+303µs) within Foswiki::Search::BEGIN@25 which was called:
# once (2.12ms+303µs) by Foswiki::search at line 25 # spent 2.42ms making 1 call to Foswiki::Search::BEGIN@25 |
26 | 2 | 154µs | 1 | 478µs | # spent 478µs (401+77) within Foswiki::Search::BEGIN@26 which was called:
# once (401µs+77µs) by Foswiki::search at line 26 # spent 478µs making 1 call to Foswiki::Search::BEGIN@26 |
27 | |||||
28 | 2 | 88µs | 2 | 235µs | # spent 127µs (20+108) within Foswiki::Search::BEGIN@28 which was called:
# once (20µs+108µs) by Foswiki::search at line 28 # spent 127µs making 1 call to Foswiki::Search::BEGIN@28
# spent 108µs making 1 call to constant::import |
29 | |||||
30 | # spent 10µs within Foswiki::Search::BEGIN@30 which was called:
# once (10µs+0s) by Foswiki::search at line 39 | ||||
31 | |||||
32 | # 'Use locale' for internationalisation of Perl sorting and searching - | ||||
33 | # main locale settings are done in Foswiki::setupLocale | ||||
34 | # Do a dynamic 'use locale' for this module | ||||
35 | 1 | 9µs | if ( $Foswiki::cfg{UseLocale} ) { | ||
36 | require locale; | ||||
37 | import locale(); | ||||
38 | } | ||||
39 | 1 | 9.54ms | 1 | 10µs | } # spent 10µs making 1 call to Foswiki::Search::BEGIN@30 |
40 | |||||
41 | =begin TML | ||||
42 | |||||
43 | ---++ ClassMethod new ($session) | ||||
44 | |||||
45 | Constructor for the singleton Search engine object. | ||||
46 | |||||
47 | =cut | ||||
48 | |||||
49 | # spent 22µs within Foswiki::Search::new which was called:
# once (22µs+0s) by Foswiki::search at line 2019 of /usr/local/src/github.com/foswiki/core/lib/Foswiki.pm | ||||
50 | 3 | 27µs | my ( $class, $session ) = @_; | ||
51 | my $this = bless( { session => $session }, $class ); | ||||
52 | |||||
53 | return $this; | ||||
54 | } | ||||
55 | |||||
56 | =begin TML | ||||
57 | |||||
58 | ---++ ObjectMethod finish() | ||||
59 | Break circular references. | ||||
60 | |||||
61 | Note to developers; please undef *all* fields in the object explicitly, | ||||
62 | whether they are references or not. That way this method is "golden | ||||
63 | documentation" of the live fields in the object. | ||||
64 | |||||
65 | =cut | ||||
66 | |||||
67 | # spent 628µs (129+499) within Foswiki::Search::finish which was called:
# once (129µs+499µs) by Foswiki::finish at line 2100 of /usr/local/src/github.com/foswiki/core/lib/Foswiki.pm | ||||
68 | 5 | 93µs | my $this = shift; | ||
69 | undef $this->{session}; | ||||
70 | |||||
71 | # these may well be function objects, but if (a setting changes, it needs to be picked up again. | ||||
72 | 2 | 21µs | if ( defined( $this->{queryParser} ) ) { | ||
73 | 1 | 8µs | $this->{queryParser}->finish(); # spent 8µs making 1 call to Foswiki::Infix::Parser::finish | ||
74 | undef $this->{queryParser}; | ||||
75 | } | ||||
76 | if ( defined( $this->{searchParser} ) ) { | ||||
77 | $this->{searchParser}->finish(); | ||||
78 | undef $this->{searchParser}; | ||||
79 | } | ||||
80 | 2 | 13µs | if ( defined( $this->{MetaCache} ) ) { | ||
81 | 1 | 491µs | $this->{MetaCache}->finish(); # spent 491µs making 1 call to Foswiki::MetaCache::finish | ||
82 | undef $this->{MetaCache}; | ||||
83 | } | ||||
84 | } | ||||
85 | |||||
86 | =begin TML | ||||
87 | |||||
88 | ---++ ObjectMethod metacache | ||||
89 | returns the metacache. | ||||
90 | |||||
91 | =cut | ||||
92 | |||||
93 | # spent 1.25ms (1.23+19µs) within Foswiki::Search::metacache which was called 145 times, avg 9µs/call:
# 55 times (551µs+19µs) by Foswiki::Meta::load at line 468 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Meta.pm, avg 10µs/call
# 22 times (179µs+0s) by Foswiki::Store::Interfaces::QueryAlgorithm::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Store/Interfaces/QueryAlgorithm.pm:187] at line 169 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Store/Interfaces/QueryAlgorithm.pm, avg 8µs/call
# 22 times (166µs+0s) by Foswiki::Store::Interfaces::QueryAlgorithm::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Store/Interfaces/QueryAlgorithm.pm:187] at line 179 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Store/Interfaces/QueryAlgorithm.pm, avg 8µs/call
# 22 times (157µs+0s) by Foswiki::Search::formatResults at line 736, avg 7µs/call
# 22 times (147µs+0s) by Foswiki::Search::formatResults at line 743, avg 7µs/call
# once (15µs+0s) by Foswiki::Users::TopicUserMapping::_getListOfGroups at line 1526 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Users/TopicUserMapping.pm
# once (11µs+0s) by Foswiki::Store::QueryAlgorithms::BruteForce::_webQuery at line 78 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Store/QueryAlgorithms/BruteForce.pm | ||||
94 | 435 | 1.39ms | my $this = shift; | ||
95 | |||||
96 | # these may well be function objects, but if (a setting changes, it needs to be picked up again. | ||||
97 | 1 | 8µs | if ( !defined( $this->{MetaCache} ) ) { | ||
98 | 1 | 19µs | $this->{MetaCache} = new Foswiki::MetaCache( $this->{session} ); # spent 19µs making 1 call to Foswiki::MetaCache::new | ||
99 | } | ||||
100 | return $this->{MetaCache}; | ||||
101 | } | ||||
102 | |||||
103 | =begin TML | ||||
104 | |||||
105 | ---++ ObjectMethod parseSearch($searchString, $params) -> Foswiki::*::Node | ||||
106 | |||||
107 | parses the search string and builds the appropriate nodes (uses $param->{type} to work out which parser | ||||
108 | |||||
109 | TODO: make parser register themselves with their type, so that we could plug in anything. | ||||
110 | |||||
111 | =cut | ||||
112 | |||||
113 | # spent 4.02ms (87µs+3.93) within Foswiki::Search::parseSearch which was called:
# once (87µs+3.93ms) by Foswiki::Search::searchWeb at line 356 | ||||
114 | 8 | 74µs | my $this = shift; | ||
115 | my $searchString = shift; | ||||
116 | my $params = shift; | ||||
117 | |||||
118 | my $query; | ||||
119 | my $theParser; | ||||
120 | 2 | 5µs | if ( $params->{type} eq 'query' ) { | ||
121 | 2 | 22µs | unless ( defined( $this->{queryParser} ) ) { | ||
122 | require Foswiki::Query::Parser; | ||||
123 | 1 | 2.10ms | $this->{queryParser} = new Foswiki::Query::Parser(); # spent 2.10ms making 1 call to Foswiki::Query::Parser::new | ||
124 | } | ||||
125 | $theParser = $this->{queryParser}; | ||||
126 | } | ||||
127 | else { | ||||
128 | unless ( defined( $this->{searchParser} ) ) { | ||||
129 | require Foswiki::Search::Parser; | ||||
130 | $this->{searchParser} = | ||||
131 | new Foswiki::Search::Parser( $this->{session} ); | ||||
132 | } | ||||
133 | $theParser = $this->{searchParser}; | ||||
134 | } | ||||
135 | # spent 1.73ms (21µs+1.71) within Foswiki::Search::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm:137] which was called:
# once (21µs+1.71ms) by Error::subs::try at line 416 of Error.pm | ||||
136 | 1 | 25µs | 1 | 1.71ms | $query = $theParser->parse( $searchString, $params ); # spent 1.71ms making 1 call to Foswiki::Infix::Parser::parse |
137 | } | ||||
138 | catch Foswiki::Infix::Error with { | ||||
139 | |||||
140 | # Pass the error on to the caller | ||||
141 | throw Error::Simple( shift->stringify() ); | ||||
142 | 3 | 37µs | }; # spent 25µs making 1 call to Error::catch
# spent 12µs making 1 call to Error::subs::with
# spent 1.79ms making 1 call to Error::subs::try, recursion: max depth 1, sum of overlapping time 1.79ms | ||
143 | |||||
144 | #print STDERR "parseSearch($searchString) => ".$query->stringify()."\n" if MONITOR; | ||||
145 | |||||
146 | return $query; | ||||
147 | } | ||||
148 | |||||
149 | sub _extractPattern { | ||||
150 | my ( $text, $pattern ) = @_; | ||||
151 | |||||
152 | # Pattern comes from topic, therefore tainted | ||||
153 | $pattern = | ||||
154 | Foswiki::Sandbox::untaint( $pattern, \&Foswiki::validatePattern ); | ||||
155 | |||||
156 | my $ok = 0; | ||||
157 | eval { | ||||
158 | |||||
159 | # The eval acts as a try block in case there is anything evil in | ||||
160 | # the pattern. | ||||
161 | $ok = 1 if ( $text =~ s/$pattern/$1/is ); | ||||
162 | }; | ||||
163 | $text = '' unless $ok; | ||||
164 | |||||
165 | return $text; | ||||
166 | } | ||||
167 | |||||
168 | # With the same argument as $pattern, returns a number which is the count of | ||||
169 | # occurences of the pattern argument. | ||||
170 | sub _countPattern { | ||||
171 | my ( $text, $pattern ) = @_; | ||||
172 | |||||
173 | $pattern = | ||||
174 | Foswiki::Sandbox::untaint( $pattern, \&Foswiki::validatePattern ); | ||||
175 | |||||
176 | my $count; | ||||
177 | try { | ||||
178 | |||||
179 | # see: perldoc -q count | ||||
180 | $count = () = $text =~ /$pattern/g; | ||||
181 | } | ||||
182 | catch Error::Simple with { | ||||
183 | $count = 0; | ||||
184 | }; | ||||
185 | |||||
186 | return $count; | ||||
187 | } | ||||
188 | |||||
189 | =begin TML | ||||
190 | |||||
191 | ---++ StaticMethod _isSetTrue( $value, $default ) -> $boolean | ||||
192 | |||||
193 | Returns 1 if =$value= is _actually set to_ true, and 0 otherwise. | ||||
194 | |||||
195 | If the value is undef, then =$default= is returned. If =$default= is | ||||
196 | not specified it is taken as 0. | ||||
197 | |||||
198 | =cut | ||||
199 | |||||
200 | sub _isSetTrue { | ||||
201 | my ( $value, $default ) = @_; | ||||
202 | |||||
203 | $default ||= 0; | ||||
204 | |||||
205 | return $default unless defined($value); | ||||
206 | |||||
207 | $value =~ s/on//gi; | ||||
208 | $value =~ s/yes//gi; | ||||
209 | $value =~ s/true//gi; | ||||
210 | return ($value) ? 0 : 1; | ||||
211 | } | ||||
212 | |||||
213 | =begin TML | ||||
214 | |||||
215 | ---++ ObjectMethod searchWeb (...) | ||||
216 | |||||
217 | Search one or more webs according to the parameters. | ||||
218 | |||||
219 | If =_callback= is set, that means the caller wants results as | ||||
220 | soon as they are ready. =_callback_ should be set to a reference | ||||
221 | to a function which takes =_cbdata= as the first parameter and | ||||
222 | remaining parameters the same as 'print'. | ||||
223 | |||||
224 | If =_callback= is set, the result is always undef. Otherwise the | ||||
225 | result is a string containing the rendered search results. | ||||
226 | |||||
227 | The function will throw Error::Simple if it encounters any problems with the | ||||
228 | syntax of the search string. | ||||
229 | |||||
230 | Note: If =format= is set, =template= will be ignored. | ||||
231 | |||||
232 | Note: For legacy, if =regex= is defined, it will force type='regex' | ||||
233 | |||||
234 | If =type="word"= it will be changed to =type="keyword"= with =wordboundaries=1=. This will be used for searching with scope="text" only, because scope="topic" will do a Perl search on topic names. | ||||
235 | |||||
236 | SMELL: If =template= is defined =bookview= will not work | ||||
237 | |||||
238 | SMELL: it seems that if you define =_callback= then you are | ||||
239 | responsible for converting the TML to HTML yourself! | ||||
240 | |||||
241 | FIXME: =callback= cannot work with format parameter (consider format='| $topic |' | ||||
242 | |||||
243 | =cut | ||||
244 | |||||
245 | # spent 3.36s (547µs+3.36) within Foswiki::Search::searchWeb which was called:
# once (547µs+3.36s) by Foswiki::Users::TopicUserMapping::_getListOfGroups at line 1532 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Users/TopicUserMapping.pm | ||||
246 | 53 | 505µs | my $this = shift; | ||
247 | my $session = $this->{session}; | ||||
248 | 1 | 4µs | ASSERT( defined $session->{webName} ) if DEBUG; # spent 4µs making 1 call to Assert::ASSERTS_OFF | ||
249 | my %params = @_; | ||||
250 | |||||
251 | 1 | 79µs | my $baseWebObject = Foswiki::Meta->new( $session, $session->{webName} ); # spent 79µs making 1 call to Foswiki::Meta::new | ||
252 | |||||
253 | 1 | 37µs | my ( $callback, $cbdata ) = setup_callback( \%params, $baseWebObject ); # spent 37µs making 1 call to Foswiki::Search::setup_callback | ||
254 | |||||
255 | my $baseTopic = $params{basetopic} || $session->{topicName}; | ||||
256 | my $baseWeb = $params{baseweb} || $session->{webName}; | ||||
257 | 1 | 8µs | $params{casesensitive} = Foswiki::isTrue( $params{casesensitive} ); # spent 8µs making 1 call to Foswiki::isTrue | ||
258 | $params{excludeTopics} = $params{excludetopic} || ''; | ||||
259 | my $formatDefined = $params{formatdefined} = defined $params{format}; | ||||
260 | my $format = $params{format}; | ||||
261 | |||||
262 | 1 | 8µs | $params{multiple} = Foswiki::isTrue( $params{multiple} ); # spent 8µs making 1 call to Foswiki::isTrue | ||
263 | 1 | 7µs | $params{nonoise} = Foswiki::isTrue( $params{nonoise} ); # spent 7µs making 1 call to Foswiki::isTrue | ||
264 | 1 | 58µs | $params{noempty} = Foswiki::isTrue( $params{noempty}, $params{nonoise} ); # spent 58µs making 1 call to Foswiki::isTrue | ||
265 | ### $params{zeroresults} = Foswiki::isTrue( ( $params{zeroresults} ), $params{nonoise} ); | ||||
266 | |||||
267 | #TODO: refactorme | ||||
268 | my $header = $params{header}; | ||||
269 | my $footer = $params{footer}; | ||||
270 | 1 | 48µs | my $noTotal = Foswiki::isTrue( $params{nototal}, $params{nonoise} ); # spent 48µs making 1 call to Foswiki::isTrue | ||
271 | |||||
272 | 1 | 43µs | my $noEmpty = Foswiki::isTrue( $params{noempty}, $params{nonoise} ); # spent 43µs making 1 call to Foswiki::isTrue | ||
273 | |||||
274 | # Note: a defined header/footer overrides noheader/nofooter | ||||
275 | # To maintain Cairo compatibility we ommit default header/footer if the | ||||
276 | 1 | 42µs | my $noHeader = # spent 42µs making 1 call to Foswiki::isTrue | ||
277 | !defined($header) | ||||
278 | && Foswiki::isTrue( $params{noheader}, $params{nonoise} ) | ||||
279 | || ( !$header && $formatDefined ); | ||||
280 | |||||
281 | 1 | 7µs | my $noFooter = # spent 7µs making 1 call to Foswiki::isTrue | ||
282 | !defined($footer) | ||||
283 | && Foswiki::isTrue( $params{nofooter}, $params{nonoise} ) | ||||
284 | || ( !$footer && $formatDefined ); | ||||
285 | |||||
286 | 1 | 42µs | my $noSummary = Foswiki::isTrue( $params{nosummary}, $params{nonoise} ); # spent 42µs making 1 call to Foswiki::isTrue | ||
287 | 1 | 7µs | my $zeroResults = # spent 7µs making 1 call to Foswiki::isTrue | ||
288 | Foswiki::isTrue( $params{zeroresults}, $params{nonoise} || 1 ); | ||||
289 | |||||
290 | #END TODO | ||||
291 | |||||
292 | 1 | 7µs | my $doBookView = Foswiki::isTrue( $params{bookview} ); # spent 7µs making 1 call to Foswiki::isTrue | ||
293 | |||||
294 | 1 | 7µs | my $revSort = Foswiki::isTrue( $params{reverse} ); # spent 7µs making 1 call to Foswiki::isTrue | ||
295 | $params{scope} = $params{scope} || ''; | ||||
296 | my $searchString = defined $params{search} ? $params{search} : ''; | ||||
297 | |||||
298 | $params{includeTopics} = $params{topic} || ''; | ||||
299 | $params{type} = $params{type} || ''; | ||||
300 | |||||
301 | $params{wordboundaries} = 0; | ||||
302 | if ( $params{type} eq 'word' ) { | ||||
303 | |||||
304 | # 'word' is exactly the same as 'keyword', except we will be searching | ||||
305 | # with word boundaries | ||||
306 | $params{type} = 'keyword'; | ||||
307 | $params{wordboundaries} = 1; | ||||
308 | } | ||||
309 | |||||
310 | my $webNames = $params{web} || ''; | ||||
311 | my $date = $params{date} || ''; | ||||
312 | my $recurse = $params{'recurse'} || ''; | ||||
313 | |||||
314 | 1 | 4µs | $baseWeb =~ s/\./\//go; # spent 4µs making 1 call to Foswiki::Search::CORE:subst | ||
315 | |||||
316 | $params{type} = 'regex' if ( $params{regex} ); | ||||
317 | |||||
318 | #TODO: quick hackjob - see what the feature proposal gives before it becomes public | ||||
319 | 1 | 3µs | if ( defined( $params{groupby} ) and ( $params{groupby} eq 'none' ) ) { | ||
320 | |||||
321 | #_only_ allow groupby="none" - as its a secrect none public setting. | ||||
322 | } | ||||
323 | else { | ||||
324 | $params{groupby} = 'web'; | ||||
325 | } | ||||
326 | |||||
327 | # need to tell the Meta::query pager settings so it can optimise | ||||
328 | require Digest::MD5; | ||||
329 | my $string_id = $params{_RAW} || 'we had better not go there'; | ||||
330 | 1 | 20µs | my $paging_ID = 'SEARCH' . Digest::MD5::md5_hex($string_id); # spent 20µs making 1 call to Digest::MD5::md5_hex | ||
331 | $params{pager_urlparam_id} = $paging_ID; | ||||
332 | |||||
333 | # 1-based system; 0 is not a valid page number | ||||
334 | 1 | 99µs | $params{showpage} = $session->{request}->param($paging_ID) # spent 99µs making 1 call to Foswiki::Request::param | ||
335 | || $params{showpage}; | ||||
336 | |||||
337 | #append a pager to the end of the search result. | ||||
338 | 1 | 8µs | $params{pager} = Foswiki::isTrue( $params{pager} ); # spent 8µs making 1 call to Foswiki::isTrue | ||
339 | |||||
340 | 1 | 2µs | if ( defined( $params{pagesize} ) | ||
341 | or defined( $params{showpage} ) | ||||
342 | or $params{pager} ) | ||||
343 | { | ||||
344 | if ( !defined( $params{pagesize} ) ) { | ||||
345 | $params{pagesize} = $Foswiki::cfg{Search}{DefaultPageSize} || 25; | ||||
346 | } | ||||
347 | $params{showpage} = 1 unless ( defined( $params{showpage} ) ); | ||||
348 | $params{paging_on} = 1; | ||||
349 | } | ||||
350 | else { | ||||
351 | |||||
352 | #denote the pager is off. | ||||
353 | $params{paging_on} = 0; | ||||
354 | } | ||||
355 | ################### Perform The Search | ||||
356 | 1 | 4.02ms | my $query = $this->parseSearch( $searchString, \%params ); # spent 4.02ms making 1 call to Foswiki::Search::parseSearch | ||
357 | |||||
358 | #setting the inputTopicSet to be undef allows the search/query algo to use | ||||
359 | #the topic="" and excludetopic="" params and web Obj to get a new list of topics. | ||||
360 | #this allows the algo's to customise and optimise the getting of this list themselves. | ||||
361 | |||||
362 | #NOTE: as of Jun2011 foswiki 1.2/2.0's query() returns a result set filtered by ACL and paged to $showpage | ||||
363 | #TODO: work out if and how to avoid it | ||||
364 | 1 | 1.66s | my $infoCache = Foswiki::Meta::query( $query, undef, \%params ); # spent 1.66s making 1 call to Foswiki::Meta::query | ||
365 | |||||
366 | ################### Do the Rendering | ||||
367 | |||||
368 | # If the search did not return anything, return the rendered zeroresults | ||||
369 | # if it is defined as a string. | ||||
370 | # (http://foswiki.org/Development/AddDefaultTopicParameterToINCLUDE) | ||||
371 | 1 | 3.63ms | if ( not $infoCache->hasNext() ) { # spent 3.63ms making 1 call to Foswiki::Iterator::FilterIterator::hasNext | ||
372 | if ( not $zeroResults ) { | ||||
373 | return ''; | ||||
374 | } | ||||
375 | else { | ||||
376 | if ( not _isSetTrue( $params{zeroresults}, 1 ) ) { | ||||
377 | |||||
378 | #foswiki 1.1 Feature Proposal: SEARCH needs an alt parameter in case of zero results | ||||
379 | |||||
380 | #TODO: extract & merge with extraction of footer processing code below | ||||
381 | my $result = $params{zeroresults}; | ||||
382 | |||||
383 | $result =~ s/\$web/$baseWeb/gos; # expand name of web | ||||
384 | $result =~ s/([^\n])$/$1\n/os; # add new line at end | ||||
385 | |||||
386 | # output footer of $web | ||||
387 | $result =~ s/\$ntopics/0/gs; | ||||
388 | $result =~ s/\$nhits/0/gs; | ||||
389 | $result =~ s/\$index/0/gs; | ||||
390 | |||||
391 | #legacy SEARCH counter support | ||||
392 | $result =~ s/%NTOPICS%/0/go; | ||||
393 | |||||
394 | $result = Foswiki::expandStandardEscapes($result); | ||||
395 | $result =~ s/\n$//os; # remove trailing new line | ||||
396 | |||||
397 | return $result; | ||||
398 | } | ||||
399 | } | ||||
400 | } | ||||
401 | |||||
402 | 1 | 10.2ms | my $tmplSearch = # spent 10.2ms making 1 call to Foswiki::Search::loadTemplates | ||
403 | $this->loadTemplates( \%params, $baseWebObject, $formatDefined, | ||||
404 | $doBookView, $noHeader, $noSummary, $noTotal, $noFooter ); | ||||
405 | |||||
406 | # Generate 'Search:' part showing actual search string used | ||||
407 | # Ommit any text before search results if either nosearch or nonoise is on | ||||
408 | 1 | 59µs | my $nonoise = Foswiki::isTrue( $params{nonoise} ); # spent 59µs making 1 call to Foswiki::isTrue | ||
409 | 1 | 43µs | my $noSearch = Foswiki::isTrue( $params{nosearch}, $nonoise ); # spent 43µs making 1 call to Foswiki::isTrue | ||
410 | unless ($noSearch) { | ||||
411 | my $searchStr = $searchString; | ||||
412 | $searchStr =~ s/&/&/go; | ||||
413 | $searchStr =~ s/</</go; | ||||
414 | $searchStr =~ s/>/>/go; | ||||
415 | |||||
416 | $tmplSearch =~ s/%SEARCHSTRING%/$searchStr/go; | ||||
417 | &$callback( $cbdata, $tmplSearch ); | ||||
418 | } | ||||
419 | |||||
420 | # We now format the results. | ||||
421 | # All the | ||||
422 | 1 | 1.68s | my ( $numberOfResults, $web_searchResult ) = # spent 1.68s making 1 call to Foswiki::Search::formatResults | ||
423 | $this->formatResults( $query, $infoCache, \%params ); | ||||
424 | |||||
425 | return if ( defined $params{_callback} ); | ||||
426 | |||||
427 | my $searchResult = join( '', @{ $params{_cbdata} } ); | ||||
428 | |||||
429 | $searchResult = Foswiki::expandStandardEscapes($searchResult); | ||||
430 | |||||
431 | # Remove trailing separator or new line if nofinalnewline parameter is set | ||||
432 | my $noFinalNewline = Foswiki::isTrue( $params{nofinalnewline}, 1 ); | ||||
433 | if ( $formatDefined && $noFinalNewline ) { | ||||
434 | if ( $params{separator} ) { | ||||
435 | my $separator = quotemeta( $params{separator} ); | ||||
436 | $searchResult =~ s/$separator$//s; # remove separator at end | ||||
437 | } | ||||
438 | else { | ||||
439 | $searchResult =~ s/\n$//os; # remove trailing new line | ||||
440 | } | ||||
441 | } | ||||
442 | |||||
443 | return $searchResult; | ||||
444 | } | ||||
445 | |||||
446 | =begin TML | ||||
447 | |||||
448 | ---++ ObjectMethod loadTemplates (...) | ||||
449 | |||||
450 | this code was extracted from searchWeb, and should probably be private. | ||||
451 | |||||
452 | =cut | ||||
453 | |||||
454 | # spent 10.2ms (242µs+10.0) within Foswiki::Search::loadTemplates which was called:
# once (242µs+10.0ms) by Foswiki::Search::searchWeb at line 402 | ||||
455 | my ( | ||||
456 | 14 | 82µs | $this, $params, $baseWebObject, | ||
457 | $formatDefined, $doBookView, $noHeader, | ||||
458 | $noSummary, $noTotal, $noFooter | ||||
459 | ) = @_; | ||||
460 | |||||
461 | my $session = $this->{session}; | ||||
462 | |||||
463 | #tmpl loading code. | ||||
464 | my $tmpl = ''; | ||||
465 | |||||
466 | my $template = $params->{template} || ''; | ||||
467 | 1 | 2µs | if ($formatDefined) { | ||
468 | $template = 'searchformat'; | ||||
469 | } | ||||
470 | elsif ($template) { | ||||
471 | |||||
472 | # template definition overrides book and rename views | ||||
473 | } | ||||
474 | elsif ($doBookView) { | ||||
475 | $template = 'searchbookview'; | ||||
476 | } | ||||
477 | else { | ||||
478 | $template = 'search'; | ||||
479 | } | ||||
480 | 2 | 8.94ms | $tmpl = $session->templates->readTemplate($template); # spent 8.93ms making 1 call to Foswiki::Templates::readTemplate
# spent 14µs making 1 call to Foswiki::templates | ||
481 | |||||
482 | #print STDERR "}}} $tmpl {{{\n"; | ||||
483 | # SMELL: the only META tags in a template will be METASEARCH | ||||
484 | # Why the heck are they being filtered???? | ||||
485 | #TODO: write a unit test that uses topic based templates with META's in them and if ok, remove. | ||||
486 | 1 | 4µs | $tmpl =~ s/\%META{.*?}\%//go; # remove %META{'parent'}% # spent 4µs making 1 call to Foswiki::Search::CORE:subst | ||
487 | |||||
488 | # Split template into 5 sections | ||||
489 | my ( $tmplHead, $tmplSearch, $tmplTable, $tmplNumber, $tmplTail ) = | ||||
490 | split( /%SPLIT%/, $tmpl ); | ||||
491 | |||||
492 | my $repeatText; | ||||
493 | |||||
494 | 5 | 130µs | if ( !defined($tmplTail) ) { | ||
495 | 2 | 336µs | $tmplSearch = $session->templates->expandTemplate('SEARCH:searched'); # spent 328µs making 1 call to Foswiki::Templates::expandTemplate
# spent 8µs making 1 call to Foswiki::templates | ||
496 | 2 | 489µs | $tmplNumber = $session->templates->expandTemplate('SEARCH:count'); # spent 481µs making 1 call to Foswiki::Templates::expandTemplate
# spent 8µs making 1 call to Foswiki::templates | ||
497 | |||||
498 | #it'd be nice to not need this if, but it seem that the noheader setting is ignored if a header= is set. truely bizzare | ||||
499 | #TODO: push up the 'noheader' evaluation to take not of this quirk | ||||
500 | #TODO: um, we die when ASSERT is on with a wide char in print | ||||
501 | unless ($noHeader) { | ||||
502 | $params->{header} = | ||||
503 | $session->templates->expandTemplate('SEARCH:header') | ||||
504 | unless defined $params->{header}; | ||||
505 | } | ||||
506 | |||||
507 | 2 | 234µs | $repeatText = $session->templates->expandTemplate('SEARCH:format'); # spent 226µs making 1 call to Foswiki::Templates::expandTemplate
# spent 9µs making 1 call to Foswiki::templates | ||
508 | |||||
509 | unless ($noFooter) { | ||||
510 | $params->{footer} = | ||||
511 | $session->templates->expandTemplate('SEARCH:footer') | ||||
512 | unless defined $params->{footer}; | ||||
513 | } | ||||
514 | } | ||||
515 | else { | ||||
516 | |||||
517 | #Historical legacy form of the search TMPL's | ||||
518 | # header and footer of $web | ||||
519 | my $beforeText; | ||||
520 | my $afterText; | ||||
521 | ( $beforeText, $repeatText, $afterText ) = | ||||
522 | split( /%REPEAT%/, $tmplTable ); | ||||
523 | |||||
524 | unless ($noHeader) { | ||||
525 | $params->{header} = $beforeText unless defined $params->{header}; | ||||
526 | } | ||||
527 | |||||
528 | unless ($noFooter) { | ||||
529 | $params->{footer} ||= $afterText; | ||||
530 | } | ||||
531 | } | ||||
532 | |||||
533 | #nosummary="on" nosearch="on" noheader="on" nototal="on" | ||||
534 | 2 | 14µs | if ($noSummary) { | ||
535 | 1 | 2µs | $repeatText =~ s/%TEXTHEAD%//go; # spent 2µs making 1 call to Foswiki::Search::CORE:subst | ||
536 | 1 | 1µs | $repeatText =~ s/ //go; # spent 1µs making 1 call to Foswiki::Search::CORE:subst | ||
537 | } | ||||
538 | else { | ||||
539 | $repeatText =~ s/%TEXTHEAD%/\$summary(searchcontext)/go; | ||||
540 | } | ||||
541 | $params->{format} ||= $repeatText; | ||||
542 | |||||
543 | $params->{footercounter} ||= $tmplNumber; | ||||
544 | |||||
545 | return $tmplSearch; | ||||
546 | } | ||||
547 | |||||
548 | =begin TML | ||||
549 | ---++ formatResults | ||||
550 | |||||
551 | the implementation of %FORMAT{}% | ||||
552 | |||||
553 | TODO: rewrite to take a resultset, a set of params? and a hash of sub's to | ||||
554 | enable evaluations of things like '$include(blah)' in format strings. | ||||
555 | |||||
556 | have a default set of replacements like $lt, $nop, $percnt, $dollar etc, and then | ||||
557 | the hash of subs can take care of %MACRO{}% specific complex to evaluate replacements.. | ||||
558 | |||||
559 | (that way we don't pre-evaluate and then subst) | ||||
560 | |||||
561 | =cut | ||||
562 | |||||
563 | # spent 1.68s (6.53ms+1.67) within Foswiki::Search::formatResults which was called 2 times, avg 840ms/call:
# once (6.32ms+1.67s) by Foswiki::Search::searchWeb at line 422
# once (208µs+168µs) by Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/FORMAT.pm:65] at line 62 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/FORMAT.pm | ||||
564 | 86 | 375µs | my ( $this, $query, $infoCache, $params ) = @_; | ||
565 | my $session = $this->{session}; | ||||
566 | my $users = $session->{users}; | ||||
567 | 2 | 52µs | my ( $callback, $cbdata ) = setup_callback($params); # spent 52µs making 2 calls to Foswiki::Search::setup_callback, avg 26µs/call | ||
568 | |||||
569 | my $baseTopic = $session->{topicName}; | ||||
570 | my $baseWeb = $session->{webName}; | ||||
571 | 2 | 18µs | my $doBookView = Foswiki::isTrue( $params->{bookview} ); # spent 18µs making 2 calls to Foswiki::isTrue, avg 9µs/call | ||
572 | 2 | 50µs | my $caseSensitive = Foswiki::isTrue( $params->{casesensitive} ); # spent 50µs making 2 calls to Foswiki::isTrue, avg 25µs/call | ||
573 | 2 | 14µs | my $doExpandVars = Foswiki::isTrue( $params->{expandvariables} ); # spent 14µs making 2 calls to Foswiki::isTrue, avg 7µs/call | ||
574 | 2 | 48µs | my $nonoise = Foswiki::isTrue( $params->{nonoise} ); # spent 48µs making 2 calls to Foswiki::isTrue, avg 24µs/call | ||
575 | 2 | 49µs | my $noSearch = Foswiki::isTrue( $params->{nosearch}, $nonoise ); # spent 49µs making 2 calls to Foswiki::isTrue, avg 25µs/call | ||
576 | my $formatDefined = defined $params->{format}; | ||||
577 | my $format = $params->{format} || ''; | ||||
578 | my $header = $params->{header} || ''; | ||||
579 | my $footer = $params->{footer} || ''; | ||||
580 | my $limit = $params->{limit} || ''; | ||||
581 | my $itemView = $params->{itemview}; | ||||
582 | |||||
583 | # Limit search results. Cannot be deprecated | ||||
584 | # Limit will still be needed for the application types of SEARCHES | ||||
585 | # even if pagesize is added as feature. Example for searching and listing | ||||
586 | # text from first 5 bullets in a formatted multiple type search | ||||
587 | 2 | 4µs | 2 | 7µs | if ( $limit =~ /(^\d+$)/o ) { # spent 7µs making 2 calls to Foswiki::Search::CORE:match, avg 3µs/call |
588 | |||||
589 | # only digits, all else is the same as | ||||
590 | # an empty string. "+10" won't work. | ||||
591 | $limit = $1; | ||||
592 | } | ||||
593 | else { | ||||
594 | |||||
595 | # change 'all' to 0, then to big number | ||||
596 | $limit = 0; | ||||
597 | } | ||||
598 | $limit = 32000 unless ($limit); | ||||
599 | |||||
600 | #pager formatting | ||||
601 | my %pager_formatting; | ||||
602 | if ( $params->{paging_on} ) #TODO: if can skip() | ||||
603 | { | ||||
604 | $limit = $infoCache->pagesize(); | ||||
605 | |||||
606 | my $paging_ID = $params->{pager_urlparam_id}; | ||||
607 | |||||
608 | # 1-based system; 0 is not a valid page number | ||||
609 | my $showpage = $infoCache->showpage(); | ||||
610 | |||||
611 | #TODO: need to ask the result set | ||||
612 | my $numberofpages = $infoCache->numberOfPages(); | ||||
613 | |||||
614 | #TODO: excuse me? | ||||
615 | my $sep = ' '; | ||||
616 | |||||
617 | my $nextidx = $showpage + 1; | ||||
618 | my $previousidx = $showpage - 1; | ||||
619 | |||||
620 | my %new_params; | ||||
621 | |||||
622 | #kill me please, i can't find a way to just load up the hash :( | ||||
623 | foreach my $key ( $session->{request}->param ) { | ||||
624 | $new_params{$key} = $session->{request}->param($key); | ||||
625 | } | ||||
626 | |||||
627 | $session->templates->readTemplate('searchformat'); | ||||
628 | |||||
629 | my $previouspagebutton = ''; | ||||
630 | my $previouspageurl = ''; | ||||
631 | if ( $previousidx >= 1 ) { | ||||
632 | $new_params{$paging_ID} = $previousidx; | ||||
633 | $previouspageurl = | ||||
634 | Foswiki::Func::getScriptUrl( $baseWeb, $baseTopic, 'view', | ||||
635 | %new_params ); | ||||
636 | $previouspagebutton = | ||||
637 | $session->templates->expandTemplate('SEARCH:pager_previous'); | ||||
638 | } | ||||
639 | my $nextpagebutton = ''; | ||||
640 | my $nextpageurl = ''; | ||||
641 | if ( $nextidx <= $numberofpages ) { | ||||
642 | $new_params{$paging_ID} = $nextidx; | ||||
643 | $nextpageurl = | ||||
644 | Foswiki::Func::getScriptUrl( $baseWeb, $baseTopic, 'view', | ||||
645 | %new_params ); | ||||
646 | $nextpagebutton = | ||||
647 | $session->templates->expandTemplate('SEARCH:pager_next'); | ||||
648 | } | ||||
649 | %pager_formatting = ( | ||||
650 | 'previouspage' => sub { return $previousidx }, | ||||
651 | 'currentpage' => sub { return $showpage }, | ||||
652 | 'nextpage' => sub { return $showpage + 1 }, | ||||
653 | 'numberofpages' => sub { return $numberofpages }, | ||||
654 | 'pagesize' => sub { return $infoCache->pagesize() }, | ||||
655 | 'previousurl' => sub { return $previouspageurl }, | ||||
656 | 'nexturl' => sub { return $nextpageurl }, | ||||
657 | 'sep' => sub { return $sep; } | ||||
658 | ); | ||||
659 | |||||
660 | $previouspagebutton = | ||||
661 | $this->formatCommon( $previouspagebutton, \%pager_formatting ); | ||||
662 | $pager_formatting{'previousbutton'} = | ||||
663 | sub { return $previouspagebutton }; | ||||
664 | |||||
665 | $nextpagebutton = | ||||
666 | $this->formatCommon( $nextpagebutton, \%pager_formatting ); | ||||
667 | $pager_formatting{'nextbutton'} = sub { return $nextpagebutton }; | ||||
668 | |||||
669 | my $pager_control = $params->{pagerformat} | ||||
670 | || $session->templates->expandTemplate('SEARCH:pager'); | ||||
671 | $pager_control = | ||||
672 | $this->formatCommon( $pager_control, \%pager_formatting ); | ||||
673 | $pager_formatting{'pager'} = sub { return $pager_control; }; | ||||
674 | } | ||||
675 | |||||
676 | #TODO: multiple is an attribute of the ResultSet | ||||
677 | 2 | 49µs | my $doMultiple = Foswiki::isTrue( $params->{multiple} ); # spent 49µs making 2 calls to Foswiki::isTrue, avg 25µs/call | ||
678 | 2 | 48µs | my $noEmpty = Foswiki::isTrue( $params->{noempty}, $nonoise ); # spent 48µs making 2 calls to Foswiki::isTrue, avg 24µs/call | ||
679 | |||||
680 | # Note: a defined header/footer overrides noheader/nofooter | ||||
681 | # To maintain Cairo compatibility we ommit default header/footer if the | ||||
682 | my $noHeader = | ||||
683 | !defined($header) && Foswiki::isTrue( $params->{noheader}, $nonoise ) | ||||
684 | || ( !$header && $formatDefined ); | ||||
685 | |||||
686 | my $noFooter = | ||||
687 | !defined($footer) && Foswiki::isTrue( $params->{nofooter}, $nonoise ) | ||||
688 | || ( !$footer && $formatDefined ); | ||||
689 | |||||
690 | 2 | 49µs | my $noSummary = Foswiki::isTrue( $params->{nosummary}, $nonoise ); # spent 49µs making 2 calls to Foswiki::isTrue, avg 25µs/call | ||
691 | 2 | 14µs | my $zeroResults = # spent 14µs making 2 calls to Foswiki::isTrue, avg 7µs/call | ||
692 | Foswiki::isTrue( ( $params->{zeroresults} ), $nonoise || 1 ); | ||||
693 | 2 | 48µs | my $noTotal = Foswiki::isTrue( $params->{nototal}, $nonoise ); # spent 48µs making 2 calls to Foswiki::isTrue, avg 24µs/call | ||
694 | my $newLine = $params->{newline} || ''; | ||||
695 | my $separator = $params->{separator}; | ||||
696 | my $type = $params->{type} || ''; | ||||
697 | |||||
698 | # output the list of topics in $web | ||||
699 | my $ntopics = 0; # number of topics in current web | ||||
700 | my $nhits = 0; # number of hits (if multiple=on) in current web | ||||
701 | my $headerDone = $noHeader; | ||||
702 | |||||
703 | my $web = $baseWeb; | ||||
704 | 2 | 114µs | my $webObject = new Foswiki::Meta( $session, $web ); # spent 114µs making 2 calls to Foswiki::Meta::new, avg 57µs/call | ||
705 | my $lastWebProcessed = ''; | ||||
706 | |||||
707 | #total number of topics and hits - not reset when we swap webs | ||||
708 | my $ttopics = 0; | ||||
709 | my $thits = 0; | ||||
710 | |||||
711 | 2 | 23µs | while ( $infoCache->hasNext() ) { # spent 17µs making 1 call to Foswiki::ListIterator::hasNext
# spent 7µs making 1 call to Foswiki::Iterator::FilterIterator::hasNext | ||
712 | 242 | 1.13ms | 22 | 443µs | my $listItem = $infoCache->next(); # spent 443µs making 22 calls to Foswiki::Iterator::FilterIterator::next, avg 20µs/call |
713 | 22 | 80µs | ASSERT( defined($listItem) ) if DEBUG; # spent 80µs making 22 calls to Assert::ASSERTS_OFF, avg 4µs/call | ||
714 | |||||
715 | ############################################################# | ||||
716 | #TOPIC specific | ||||
717 | my $topic = $listItem; | ||||
718 | my $text; #undef means the formatResult() gets it from $info->text; | ||||
719 | my $info; | ||||
720 | my @multipleHitLines = (); | ||||
721 | 198 | 891µs | 44 | 170µs | if ( # spent 170µs making 44 calls to UNIVERSAL::isa, avg 4µs/call |
722 | ( $infoCache->isa('Foswiki::Search::ResultSet') ) or #SEARCH | ||||
723 | ( $infoCache->isa('Foswiki::Iterator::FilterIterator') ) or #SEARCH | ||||
724 | ( $infoCache->isa('Foswiki::Iterator::PagerIterator') ) or #SEARCH | ||||
725 | ( $infoCache->isa('Foswiki::Search::InfoCache') ) #FORMAT | ||||
726 | ) | ||||
727 | { | ||||
728 | 22 | 1.78ms | ( $web, $topic ) = # spent 1.78ms making 22 calls to Foswiki::Func::normalizeWebTopicName, avg 81µs/call | ||
729 | Foswiki::Func::normalizeWebTopicName( '', $listItem ); | ||||
730 | |||||
731 | # add dependencies (TODO: unclear if this should be before the paging, or after the allowView - sadly, it can't be _in_ the infoCache) | ||||
732 | if ( my $cache = $session->{cache} ) { | ||||
733 | $cache->addDependency( $web, $topic ); | ||||
734 | } | ||||
735 | |||||
736 | 44 | 971µs | my $topicMeta = $this->metacache->getMeta( $web, $topic ); # spent 815µs making 22 calls to Foswiki::MetaCache::getMeta, avg 37µs/call
# spent 157µs making 22 calls to Foswiki::Search::metacache, avg 7µs/call | ||
737 | if ( not defined($topicMeta) ) { | ||||
738 | |||||
739 | #TODO: OMG! Search.pm relies on Meta::load (in the metacache) returning a meta object even when the topic does not exist. | ||||
740 | #lets change that | ||||
741 | $topicMeta = new Foswiki::Meta( $session, $web, $topic ); | ||||
742 | } | ||||
743 | 44 | 3.08ms | $info = $this->metacache->get( $web, $topic, $topicMeta ); # spent 2.93ms making 22 calls to Foswiki::MetaCache::get, avg 133µs/call
# spent 147µs making 22 calls to Foswiki::Search::metacache, avg 7µs/call | ||
744 | 22 | 78µs | ASSERT( defined( $info->{tom} ) ) if DEBUG; # spent 78µs making 22 calls to Assert::ASSERTS_OFF, avg 4µs/call | ||
745 | |||||
746 | $text = ''; | ||||
747 | |||||
748 | # Special handling for format='...' | ||||
749 | 66 | 229µs | if ($formatDefined) { | ||
750 | 22 | 486µs | $text = $info->{tom}->text(); # spent 486µs making 22 calls to Foswiki::Meta::text, avg 22µs/call | ||
751 | $text = '' unless defined $text; | ||||
752 | |||||
753 | if ($doExpandVars) { | ||||
754 | if ( $web eq $baseWeb && $topic eq $baseTopic ) { | ||||
755 | |||||
756 | # primitive way to prevent recursion | ||||
757 | $text =~ s/%SEARCH/%<nop>SEARCH/g; | ||||
758 | } | ||||
759 | $text = $info->{tom}->expandMacros($text); | ||||
760 | } | ||||
761 | } | ||||
762 | |||||
763 | #TODO: should extract this somehow | ||||
764 | |||||
765 | if ( $doMultiple && !$query->isEmpty() ) { | ||||
766 | |||||
767 | #TODO: Sven wonders if this should be a HoistRE.. | ||||
768 | #TODO: well, um, and how does this work for query search? | ||||
769 | my @tokens = @{ $query->tokens() }; | ||||
770 | my $pattern = $tokens[$#tokens]; # last token in an AND search | ||||
771 | $pattern = quotemeta($pattern) if ( $type ne 'regex' ); | ||||
772 | $text = $info->{tom}->text() unless defined $text; | ||||
773 | $text = '' unless defined $text; | ||||
774 | |||||
775 | if ($caseSensitive) { | ||||
776 | @multipleHitLines = | ||||
777 | reverse grep { /$pattern/ } split( /[\n\r]+/, $text ); | ||||
778 | } | ||||
779 | else { | ||||
780 | @multipleHitLines = | ||||
781 | reverse grep { /$pattern/i } split( /[\n\r]+/, $text ); | ||||
782 | } | ||||
783 | } | ||||
784 | } | ||||
785 | |||||
786 | $ntopics += 1; | ||||
787 | $ttopics += 1; | ||||
788 | 286 | 1.41ms | do { # multiple=on loop | ||
789 | |||||
790 | $nhits += 1; | ||||
791 | $thits += 1; | ||||
792 | |||||
793 | $text = pop(@multipleHitLines) if ( scalar(@multipleHitLines) ); | ||||
794 | |||||
795 | my $justdidHeaderOrFooter = 0; | ||||
796 | 22 | 37µs | if ( ( defined( $params->{groupby} ) ) | ||
797 | and ( $params->{groupby} eq 'web' ) ) | ||||
798 | { | ||||
799 | 2 | 3µs | if ( $lastWebProcessed ne $web ) { | ||
800 | |||||
801 | #output the footer for the previous listItem | ||||
802 | if ( $lastWebProcessed ne '' ) { | ||||
803 | |||||
804 | #c&p from below | ||||
805 | #TODO: needs refactoring. | ||||
806 | my $processedfooter = $footer; | ||||
807 | if ( not $noTotal ) { | ||||
808 | $processedfooter .= $params->{footercounter}; | ||||
809 | } | ||||
810 | if ( defined($processedfooter) | ||||
811 | and ( $processedfooter ne '' ) ) | ||||
812 | { | ||||
813 | |||||
814 | #footer comes before result | ||||
815 | $ntopics--; | ||||
816 | $nhits--; | ||||
817 | |||||
818 | #because $pager contains more $ntopics like format strings, it needs to be expanded first. | ||||
819 | $processedfooter = | ||||
820 | $this->formatCommon( $processedfooter, | ||||
821 | \%pager_formatting ); | ||||
822 | $processedfooter =~ s/\$web/$lastWebProcessed/gos | ||||
823 | ; # expand name of web | ||||
824 | |||||
825 | # $processedfooter =~ | ||||
826 | # s/([^\n])$/$1\n/os; # add new line at end | ||||
827 | # output footer of $web | ||||
828 | |||||
829 | $processedfooter =~ s/\$ntopics/$ntopics/gs; | ||||
830 | $processedfooter =~ s/\$nhits/$nhits/gs; | ||||
831 | $processedfooter =~ s/\$index/$thits/gs; | ||||
832 | |||||
833 | #legacy SEARCH counter support | ||||
834 | $processedfooter =~ s/%NTOPICS%/$ntopics/go; | ||||
835 | |||||
836 | $processedfooter = | ||||
837 | $this->formatCommon( $processedfooter, | ||||
838 | \%pager_formatting ); | ||||
839 | |||||
840 | # $processedfooter =~ | ||||
841 | # s/\n$//os; # remove trailing new line | ||||
842 | |||||
843 | $justdidHeaderOrFooter = 1; | ||||
844 | &$callback( $cbdata, $processedfooter ); | ||||
845 | |||||
846 | #go back to counting results | ||||
847 | $ntopics++; | ||||
848 | $nhits++; | ||||
849 | } | ||||
850 | } | ||||
851 | |||||
852 | #trigger a header for this new web | ||||
853 | $headerDone = undef; | ||||
854 | } | ||||
855 | } | ||||
856 | |||||
857 | 4 | 14µs | if ( $lastWebProcessed ne $web ) { | ||
858 | 1 | 52µs | $webObject = new Foswiki::Meta( $session, $web ); # spent 52µs making 1 call to Foswiki::Meta::new | ||
859 | $lastWebProcessed = $web; | ||||
860 | |||||
861 | #reset our web partitioned legacy counts | ||||
862 | $ntopics = 1; | ||||
863 | $nhits = 1; | ||||
864 | } | ||||
865 | |||||
866 | # lazy output of header (only if needed for the first time) | ||||
867 | if ( ( !$headerDone and ( defined($header) ) ) | ||||
868 | and ( $header ne '' ) ) | ||||
869 | { | ||||
870 | |||||
871 | my $processedheader = $header; | ||||
872 | |||||
873 | # because $pager contains more $ntopics like format | ||||
874 | # strings, it needs to be expanded first. | ||||
875 | $processedheader = | ||||
876 | $this->formatCommon( $processedheader, \%pager_formatting ); | ||||
877 | $processedheader =~ s/\$web/$web/gos; # expand name of web | ||||
878 | |||||
879 | # add new line after the header unless separator is defined | ||||
880 | # per Item1773 / SearchSeparatorDefaultHeaderFooter | ||||
881 | unless ( defined $separator ) { | ||||
882 | $processedheader =~ s/([^\n])$/$1\n/os; | ||||
883 | } | ||||
884 | |||||
885 | $headerDone = 1; | ||||
886 | my $thisWebBGColor = $webObject->getPreference('WEBBGCOLOR') | ||||
887 | || '\#FF00FF'; | ||||
888 | $processedheader =~ s/%WEBBGCOLOR%/$thisWebBGColor/go; | ||||
889 | $processedheader =~ s/%WEB%/$web/go; | ||||
890 | $processedheader =~ s/\$ntopics/($ntopics-1)/gse; | ||||
891 | $processedheader =~ s/\$nhits/($nhits-1)/gse; | ||||
892 | $processedheader =~ s/\$index/($thits-1)/gs; | ||||
893 | $processedheader = | ||||
894 | $this->formatCommon( $processedheader, \%pager_formatting ); | ||||
895 | &$callback( $cbdata, $processedheader ); | ||||
896 | $justdidHeaderOrFooter = 1; | ||||
897 | } | ||||
898 | |||||
899 | 21 | 128µs | if ( defined($separator) | ||
900 | and ( $thits > 1 ) | ||||
901 | and ( $justdidHeaderOrFooter != 1 ) ) | ||||
902 | { | ||||
903 | 21 | 662µs | &$callback( $cbdata, $separator ); # spent 662µs making 21 calls to Foswiki::Search::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm:1327], avg 32µs/call | ||
904 | } | ||||
905 | |||||
906 | ###################Render the result | ||||
907 | my $out; | ||||
908 | my $handleRev1Info = sub { | ||||
909 | |||||
910 | # Handle e.g. createdate, createwikiuser etc | ||||
911 | my $info = | ||||
912 | $this->metacache->get( $_[1]->web, $_[1]->topic, $_[1] ); | ||||
913 | my $r = $info->{tom}->getRev1Info( $_[0] ); | ||||
914 | return $r; | ||||
915 | }; | ||||
916 | my $handleRevInfo = sub { | ||||
917 | return $session->renderer->renderRevisionInfo( | ||||
918 | $_[1], | ||||
919 | $info->{revNum} || 0, | ||||
920 | '$' . $_[0] | ||||
921 | ); | ||||
922 | }; | ||||
923 | |||||
924 | 198 | 2.27ms | if ( $formatDefined and ( $format ne '' ) ) { | ||
925 | |||||
926 | # SMELL: hack to convert a bad SEARCH format to the one | ||||
927 | # used by getRevInfo.. | ||||
928 | 22 | 40µs | $format =~ s/\$createdate/\$createlongdate/gs; # spent 40µs making 22 calls to Foswiki::Search::CORE:subst, avg 2µs/call | ||
929 | |||||
930 | # SMELL: it looks like $isodate in format is equive to $iso | ||||
931 | # in renderRevisionInfo | ||||
932 | # SMELL: clean these 3 hacks up | ||||
933 | 22 | 28µs | $format =~ s/\$isodate/\$iso/gs; # spent 28µs making 22 calls to Foswiki::Search::CORE:subst, avg 1µs/call | ||
934 | 22 | 38µs | $format =~ s/\%TIME\%/\$date/gs; # spent 38µs making 22 calls to Foswiki::Search::CORE:subst, avg 2µs/call | ||
935 | 22 | 30µs | $format =~ s/\$date/\$longdate/gs; # spent 30µs making 22 calls to Foswiki::Search::CORE:subst, avg 1µs/call | ||
936 | |||||
937 | # other tmpl based renderings | ||||
938 | 22 | 36µs | $format =~ s/%WEB%/\$web/go; # spent 36µs making 22 calls to Foswiki::Search::CORE:subst, avg 2µs/call | ||
939 | 22 | 42µs | $format =~ s/%TOPICNAME%/\$topic/go; # spent 42µs making 22 calls to Foswiki::Search::CORE:subst, avg 2µs/call | ||
940 | 22 | 29µs | $format =~ s/%AUTHOR%/\$wikiusername/g; # spent 29µs making 22 calls to Foswiki::Search::CORE:subst, avg 1µs/call | ||
941 | |||||
942 | # pass search options to summary parser | ||||
943 | 22 | 123µs | my $searchOptions = { # spent 123µs making 22 calls to Foswiki::Query::Node::tokens, avg 6µs/call | ||
944 | type => $params->{type}, | ||||
945 | wordboundaries => $params->{wordboundaries}, | ||||
946 | casesensitive => $caseSensitive, | ||||
947 | tokens => $query ? $query->tokens() : undef, | ||||
948 | }; | ||||
949 | |||||
950 | # SMELL: why is this not part of the callback? at least the | ||||
951 | # non-result element format strings can be common here. | ||||
952 | # or does Sven need a formatCommon sub that formatResult can | ||||
953 | # also call.. (which then goes into the callback? | ||||
954 | $out = $this->formatResult( | ||||
955 | $format, | ||||
956 | $info->{tom} || $webObject, #SMELL: horrid hack | ||||
957 | $text, | ||||
958 | $searchOptions, | ||||
959 | { | ||||
960 | 'ntopics' => sub { return $ntopics }, | ||||
961 | 'nhits' => sub { return $nhits }, | ||||
962 | 'index' => sub { return $thits }, | ||||
963 | 'item' => sub { return $listItem }, | ||||
964 | |||||
965 | %pager_formatting, | ||||
966 | |||||
967 | 22 | 154µs | # spent 95µs within Foswiki::Search::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm:967] which was called 22 times, avg 4µs/call:
# 22 times (95µs+0s) by Foswiki::Search::formatResult at line 1115, avg 4µs/call | ||
968 | 22 | 122µs | # spent 81µs within Foswiki::Search::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm:968] which was called 22 times, avg 4µs/call:
# 22 times (81µs+0s) by Foswiki::Search::formatResult at line 1116, avg 4µs/call | ||
969 | 22 | 120µs | # spent 83µs within Foswiki::Search::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm:969] which was called 22 times, avg 4µs/call:
# 22 times (83µs+0s) by Foswiki::Search::formatResult at line 1117, avg 4µs/call | ||
970 | 22 | 117µs | # spent 80µs within Foswiki::Search::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm:970] which was called 22 times, avg 4µs/call:
# 22 times (80µs+0s) by Foswiki::Search::formatResult at line 1118, avg 4µs/call | ||
971 | 22 | 115µs | # spent 79µs within Foswiki::Search::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm:971] which was called 22 times, avg 4µs/call:
# 22 times (79µs+0s) by Foswiki::Search::formatResult at line 1119, avg 4µs/call | ||
972 | 22 | 112µs | # spent 77µs within Foswiki::Search::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm:972] which was called 22 times, avg 3µs/call:
# 22 times (77µs+0s) by Foswiki::Search::formatResult at line 1120, avg 3µs/call | ||
973 | 22 | 110µs | # spent 74µs within Foswiki::Search::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm:973] which was called 22 times, avg 3µs/call:
# 22 times (74µs+0s) by Foswiki::Search::formatResult at line 1121, avg 3µs/call | ||
974 | 22 | 110µs | # spent 74µs within Foswiki::Search::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm:974] which was called 22 times, avg 3µs/call:
# 22 times (74µs+0s) by Foswiki::Search::formatResult at line 1122, avg 3µs/call | ||
975 | 22 | 110µs | # spent 73µs within Foswiki::Search::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm:975] which was called 22 times, avg 3µs/call:
# 22 times (73µs+0s) by Foswiki::Search::formatResult at line 1123, avg 3µs/call | ||
976 | }, | ||||
977 | { | ||||
978 | |||||
979 | #rev1 info | ||||
980 | # TODO: move the $create* formats into Render::renderRevisionInfo.. | ||||
981 | # which implies moving the infocache's pre-extracted data into the tom obj too. | ||||
982 | # $out =~ s/\$create(longdate|username|wikiname|wikiusername)/ | ||||
983 | # $infoCache->getRev1Info( $topic, "create$1" )/ges; | ||||
984 | 'createlongdate' => $handleRev1Info, | ||||
985 | 'createusername' => $handleRev1Info, | ||||
986 | 'createwikiname' => $handleRev1Info, | ||||
987 | 'createwikiusername' => $handleRev1Info, | ||||
988 | 'createusername' => $handleRev1Info, | ||||
989 | |||||
990 | # rev info | ||||
991 | 'web' => sub { return $_[1]->web }, | ||||
992 | # spent 466µs (303+162) within Foswiki::Search::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm:1000] which was called 22 times, avg 21µs/call:
# 22 times (303µs+162µs) by Foswiki::Search::formatResult at line 1169, avg 21µs/call | ||||
993 | 44 | 262µs | if ( defined $_[2] ) { | ||
994 | return Foswiki::Render::breakName( $_[1]->topic, | ||||
995 | $_[2] ); | ||||
996 | } | ||||
997 | else { | ||||
998 | 22 | 162µs | return $_[1]->topic; # spent 162µs making 22 calls to Foswiki::Meta::topic, avg 7µs/call | ||
999 | } | ||||
1000 | }, | ||||
1001 | 22 | 19.2ms | 'rev' => $handleRevInfo, # spent 19.2ms making 22 calls to Foswiki::Search::formatResult, avg 873µs/call | ||
1002 | 'wikiusername' => $handleRevInfo, | ||||
1003 | 'wikiname' => $handleRevInfo, | ||||
1004 | 'username' => $handleRevInfo, | ||||
1005 | 'iso' => $handleRevInfo, | ||||
1006 | 'longdate' => $handleRevInfo, | ||||
1007 | 'date' => $handleRevInfo, | ||||
1008 | } | ||||
1009 | ); | ||||
1010 | } | ||||
1011 | else { | ||||
1012 | $out = ''; | ||||
1013 | } | ||||
1014 | |||||
1015 | 22 | 810µs | &$callback( $cbdata, $out ); # spent 810µs making 22 calls to Foswiki::Search::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm:1327], avg 37µs/call | ||
1016 | } while (@multipleHitLines); # multiple=on loop | ||||
1017 | |||||
1018 | 22 | 35µs | 22 | 1.64s | if ( # spent 1.64s making 22 calls to Foswiki::Iterator::FilterIterator::hasNext, avg 74.7ms/call |
1019 | ( $params->{paging_on} ) | ||||
1020 | or ( ( defined( $params->{groupby} ) ) | ||||
1021 | and ( $params->{groupby} ne 'web' ) ) | ||||
1022 | ) | ||||
1023 | { | ||||
1024 | last if ( $ttopics >= $limit ); | ||||
1025 | } | ||||
1026 | else { | ||||
1027 | if ( $ntopics >= $limit ) { | ||||
1028 | $infoCache->nextWeb(); | ||||
1029 | } | ||||
1030 | } | ||||
1031 | } # end topic loop | ||||
1032 | |||||
1033 | # output footer only if hits in web | ||||
1034 | 3 | 6µs | if ( $ntopics == 0 ) { | ||
1035 | 1 | 2µs | if ( $zeroResults and not $noTotal ) { | ||
1036 | $footer = $params->{footercounter}; | ||||
1037 | } | ||||
1038 | else { | ||||
1039 | $footer = ''; | ||||
1040 | } | ||||
1041 | ##MOVEDUP $webObject = new Foswiki::Meta( $session, $baseWeb ); | ||||
1042 | } | ||||
1043 | else { | ||||
1044 | if ( ( not $noTotal ) and ( defined( $params->{footercounter} ) ) ) { | ||||
1045 | $footer .= $params->{footercounter}; | ||||
1046 | } | ||||
1047 | |||||
1048 | if ( $params->{pager} ) { | ||||
1049 | |||||
1050 | #auto-append the pager | ||||
1051 | $footer .= '$pager'; | ||||
1052 | } | ||||
1053 | } | ||||
1054 | 7 | 57µs | if ( defined $footer ) { | ||
1055 | |||||
1056 | #because $pager contains more $ntopics like format strings, it needs to be expanded first. | ||||
1057 | 1 | 16µs | $footer = $this->formatCommon( $footer, \%pager_formatting ); # spent 16µs making 1 call to Foswiki::Search::formatCommon | ||
1058 | 1 | 2µs | $footer =~ s/\$web/$web/gos; # expand name of web # spent 2µs making 1 call to Foswiki::Search::CORE:subst | ||
1059 | |||||
1060 | # $footer =~ s/([^\n])$/$1\n/os; # add new line at end | ||||
1061 | |||||
1062 | # output footer of $web | ||||
1063 | 1 | 1µs | $footer =~ s/\$ntopics/$ntopics/gs; # spent 1µs making 1 call to Foswiki::Search::CORE:subst | ||
1064 | 1 | 1µs | $footer =~ s/\$nhits/$nhits/gs; # spent 1µs making 1 call to Foswiki::Search::CORE:subst | ||
1065 | 1 | 1µs | $footer =~ s/\$index/$thits/gs; # spent 1µs making 1 call to Foswiki::Search::CORE:subst | ||
1066 | |||||
1067 | #legacy SEARCH counter support | ||||
1068 | 1 | 1µs | $footer =~ s/%NTOPICS%/$ntopics/go; # spent 1µs making 1 call to Foswiki::Search::CORE:subst | ||
1069 | |||||
1070 | # $footer =~ s/\n$//os; # remove trailing new line | ||||
1071 | |||||
1072 | 1 | 28µs | &$callback( $cbdata, $footer ); # spent 28µs making 1 call to Foswiki::Search::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm:1327] | ||
1073 | } | ||||
1074 | |||||
1075 | return ( $ntopics, | ||||
1076 | ( ( not defined( $params->{_callback} ) ) and ( $nhits >= 0 ) ) | ||||
1077 | ? join( '', @$cbdata ) | ||||
1078 | : '' ); | ||||
1079 | } | ||||
1080 | |||||
1081 | # spent 16µs within Foswiki::Search::formatCommon which was called:
# once (16µs+0s) by Foswiki::Search::formatResults at line 1057 | ||||
1082 | 4 | 23µs | my ( $this, $out, $customKeys ) = @_; | ||
1083 | |||||
1084 | my $session = $this->{session}; | ||||
1085 | |||||
1086 | foreach my $key ( keys(%$customKeys) ) { | ||||
1087 | $out =~ s/\$$key/&{$customKeys->{$key}}()/ges; | ||||
1088 | } | ||||
1089 | |||||
1090 | return $out; | ||||
1091 | } | ||||
1092 | |||||
1093 | =begin TML | ||||
1094 | |||||
1095 | ---++ ObjectMethod formatResult | ||||
1096 | * $text can be undefined. | ||||
1097 | * $searchOptions is an options hash to pass on to the summary parser | ||||
1098 | * $nonTomKeys is a hash of key -> sub($key,$item) where $item is *not* assumed to be a topic object. | ||||
1099 | * tomKeys is a hash of {'$key' => sub($key,$item,$params) } | ||||
1100 | where $item is a tom object (initially a Foswiki::Meta, but I'd like to be more generic) and $params is whatever is in trailing () | ||||
1101 | |||||
1102 | TODO: i don't really know what we'll need to do about order of processing. | ||||
1103 | TODO: at minimum, the keys need to be sorted by length so that $datatime is processed before $date | ||||
1104 | TODO: need to cater for $summary(params) style too | ||||
1105 | |||||
1106 | =cut | ||||
1107 | |||||
1108 | # spent 19.2ms (9.99+9.22) within Foswiki::Search::formatResult which was called 22 times, avg 873µs/call:
# 22 times (9.99ms+9.22ms) by Foswiki::Search::formatResults at line 1001, avg 873µs/call | ||||
1109 | 462 | 2.47ms | my ( $this, $out, $item, $text, $searchOptions, $nonTomKeys, $tomKeys ) = | ||
1110 | @_; | ||||
1111 | |||||
1112 | my $session = $this->{session}; | ||||
1113 | |||||
1114 | #TODO: these need to go away. | ||||
1115 | 22 | 38µs | 22 | 95µs | my $revNum = &{ $nonTomKeys->{'revNum'} }(); # spent 95µs making 22 calls to Foswiki::Search::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm:967], avg 4µs/call |
1116 | 22 | 37µs | 22 | 81µs | my $doBookView = &{ $nonTomKeys->{'doBookView'} }(); # spent 81µs making 22 calls to Foswiki::Search::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm:968], avg 4µs/call |
1117 | 22 | 37µs | 22 | 83µs | my $baseWeb = &{ $nonTomKeys->{'baseWeb'} }(); # spent 83µs making 22 calls to Foswiki::Search::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm:969], avg 4µs/call |
1118 | 22 | 35µs | 22 | 80µs | my $baseTopic = &{ $nonTomKeys->{'baseTopic'} }(); # spent 80µs making 22 calls to Foswiki::Search::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm:970], avg 4µs/call |
1119 | 22 | 36µs | 22 | 79µs | my $newLine = &{ $nonTomKeys->{'newLine'} }(); # spent 79µs making 22 calls to Foswiki::Search::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm:971], avg 4µs/call |
1120 | 22 | 37µs | 22 | 77µs | my $separator = &{ $nonTomKeys->{'separator'} }(); # spent 77µs making 22 calls to Foswiki::Search::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm:972], avg 3µs/call |
1121 | 22 | 36µs | 22 | 74µs | my $noTotal = &{ $nonTomKeys->{'noTotal'} }(); # spent 74µs making 22 calls to Foswiki::Search::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm:973], avg 3µs/call |
1122 | 22 | 41µs | 22 | 74µs | my $params = &{ $nonTomKeys->{'paramsHash'} }(); # spent 74µs making 22 calls to Foswiki::Search::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm:974], avg 3µs/call |
1123 | 22 | 49µs | 22 | 73µs | my $itemView = &{ $nonTomKeys->{'itemView'} }(); # spent 73µs making 22 calls to Foswiki::Search::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm:975], avg 3µs/call |
1124 | foreach my $key ( | ||||
1125 | 'revNum', 'doBookView', 'baseWeb', 'baseTopic', | ||||
1126 | 'newLine', 'separator', 'noTotal', 'paramsHash', | ||||
1127 | 'itemView' | ||||
1128 | ) | ||||
1129 | { | ||||
1130 | 396 | 818µs | delete $tomKeys->{$key}; | ||
1131 | delete $nonTomKeys->{$key}; | ||||
1132 | } | ||||
1133 | |||||
1134 | # render each item differently, based on SEARCH param 'itemview' | ||||
1135 | 22 | 207µs | if ( $item->topic # spent 207µs making 22 calls to Foswiki::Meta::topic, avg 9µs/call | ||
1136 | && defined $itemView | ||||
1137 | && $itemView =~ /([$Foswiki::regex{mixedAlphaNum}.\s\(\)\$]+)/o ) | ||||
1138 | { | ||||
1139 | |||||
1140 | # brackets added to regex to allow $formfield(name) | ||||
1141 | |||||
1142 | # add to skinpath - only to pass as param to readTemplate | ||||
1143 | $itemView = $1; | ||||
1144 | |||||
1145 | # parse formatted search tokens | ||||
1146 | $itemView =~ | ||||
1147 | s/\$formfield\(\s*([^\)]*)\s*\)/displayFormField( $item, $1 )/ges; | ||||
1148 | foreach my $key ( keys(%$tomKeys) ) { | ||||
1149 | $itemView =~ s[\$$key(?:\(([^\)]*)\))?] | ||||
1150 | [&{$tomKeys->{$key}}($key, $item, $1)]ges; | ||||
1151 | } | ||||
1152 | |||||
1153 | # load the appropriate template for this item | ||||
1154 | my $tmpl = | ||||
1155 | $session->templates->readTemplate( ucfirst $itemView . 'ItemView' ); | ||||
1156 | my $text = $session->templates->expandTemplate('LISTITEM'); | ||||
1157 | $out = $text if $text; | ||||
1158 | } | ||||
1159 | |||||
1160 | foreach my $key ( keys(%$nonTomKeys) ) { | ||||
1161 | 88 | 1.69ms | 176 | 875µs | $out =~ s/\$$key/&{$nonTomKeys->{$key}}($key, $item)/ges; # spent 735µs making 88 calls to Foswiki::Search::CORE:regcomp, avg 8µs/call
# spent 140µs making 88 calls to Foswiki::Search::CORE:subst, avg 2µs/call |
1162 | |||||
1163 | #print STDERR "1: $key $out\n"; | ||||
1164 | } | ||||
1165 | 44 | 305µs | 22 | 169µs | if ( $item->topic ) { # spent 169µs making 22 calls to Foswiki::Meta::topic, avg 8µs/call |
1166 | |||||
1167 | # Only process tomKeys if the item is a valid topicObject | ||||
1168 | foreach my $key ( keys(%$tomKeys) ) { | ||||
1169 | 330 | 6.68ms | 638 | 4.14ms | $out =~ s[\$$key(?:\(([^\)]*)\))?] # spent 2.99ms making 286 calls to Foswiki::Search::CORE:regcomp, avg 10µs/call
# spent 579µs making 286 calls to Foswiki::Search::CORE:subst, avg 2µs/call
# spent 466µs making 22 calls to Foswiki::Search::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm:1000], avg 21µs/call
# spent 107µs making 44 calls to Foswiki::Search::CORE:substcont, avg 2µs/call |
1170 | [&{$tomKeys->{$key}}($key, $item, $1)]ges; | ||||
1171 | } | ||||
1172 | |||||
1173 | # Note that we cannot send a formatted search through renderRevisionInfo | ||||
1174 | # without expanding tokens we should not because the function also sends | ||||
1175 | # the input through formatTime and probably other nasty filters | ||||
1176 | # So we send each token through one by one. | ||||
1177 | 22 | 50µs | if ( $out =~ m/\$text/ ) { # spent 50µs making 22 calls to Foswiki::Search::CORE:match, avg 2µs/call | ||
1178 | $text = $item->text() unless defined $text; | ||||
1179 | $text = '' unless defined $text; | ||||
1180 | |||||
1181 | if ( $item->topic eq $session->{topicName} ) { | ||||
1182 | |||||
1183 | #TODO: extract the diffusion and generalise to whatever MACRO we are processing - anything with a format can loop | ||||
1184 | |||||
1185 | # defuse SEARCH in current topic to prevent loop | ||||
1186 | $text =~ s/%SEARCH{.*?}%/SEARCH{...}/go; | ||||
1187 | } | ||||
1188 | $out =~ s/\$text/$text/gos; | ||||
1189 | } | ||||
1190 | } | ||||
1191 | foreach my $key ( keys(%$nonTomKeys) ) { | ||||
1192 | 88 | 1.54ms | 176 | 737µs | $out =~ s/\$$key/&{$nonTomKeys->{$key}}($key, $item)/ges; # spent 591µs making 88 calls to Foswiki::Search::CORE:regcomp, avg 7µs/call
# spent 146µs making 88 calls to Foswiki::Search::CORE:subst, avg 2µs/call |
1193 | |||||
1194 | #print STDERR "2: $key $out\n"; | ||||
1195 | } | ||||
1196 | |||||
1197 | #TODO: extract the rev | ||||
1198 | my $srev = 'r' . $revNum; | ||||
1199 | 6 | 150µs | if ( $revNum eq '0' || $revNum eq '1' ) { | ||
1200 | 18 | 1.66ms | $srev = CGI::span( { class => 'foswikiNew' }, # spent 803µs making 5 calls to CGI::span, avg 161µs/call
# spent 596µs making 1 call to CGI::AUTOLOAD
# spent 198µs making 6 calls to Foswiki::I18N::Fallback::maketext, avg 33µs/call
# spent 62µs making 6 calls to Foswiki::i18n, avg 10µs/call | ||
1201 | ( $session->i18n->maketext('NEW') ) ); | ||||
1202 | } | ||||
1203 | 22 | 39µs | $out =~ s/%REVISION%/$srev/o; # spent 39µs making 22 calls to Foswiki::Search::CORE:subst, avg 2µs/call | ||
1204 | |||||
1205 | 66 | 221µs | if ($doBookView) { | ||
1206 | |||||
1207 | # BookView | ||||
1208 | $text = $item->text() unless defined $text; | ||||
1209 | $text = '' unless defined $text; | ||||
1210 | |||||
1211 | if ( $item->web eq $baseWeb && $item->topic eq $baseTopic ) { | ||||
1212 | |||||
1213 | # primitive way to prevent recursion | ||||
1214 | $text =~ s/%SEARCH/%<nop>SEARCH/g; | ||||
1215 | } | ||||
1216 | $text = $item->expandMacros($text); | ||||
1217 | $text = $item->renderTML($text); | ||||
1218 | |||||
1219 | $out =~ s/%TEXTHEAD%/$text/go; | ||||
1220 | |||||
1221 | } | ||||
1222 | else { | ||||
1223 | |||||
1224 | #TODO: more topic specific bits | ||||
1225 | 176 | 975µs | 22 | 176µs | if ( defined( $item->topic ) ) { # spent 176µs making 22 calls to Foswiki::Meta::topic, avg 8µs/call |
1226 | 22 | 48µs | $out =~ s/\$summary(?:\(([^\)]*)\))?/ # spent 48µs making 22 calls to Foswiki::Search::CORE:subst, avg 2µs/call | ||
1227 | $item->summariseText( $1, $text, $searchOptions )/ges; | ||||
1228 | 22 | 33µs | $out =~ s/\$changes(?:\(([^\)]*)\))?/ # spent 33µs making 22 calls to Foswiki::Search::CORE:subst, avg 2µs/call | ||
1229 | $item->summariseChanges(Foswiki::Store::cleanUpRevID($1), $revNum)/ges; | ||||
1230 | 22 | 31µs | $out =~ s/\$formfield\(\s*([^\)]*)\s*\)/ # spent 31µs making 22 calls to Foswiki::Search::CORE:subst, avg 1µs/call | ||
1231 | displayFormField( $item, $1 )/ges; | ||||
1232 | 22 | 32µs | $out =~ s/\$parent\(([^\)]*)\)/ # spent 32µs making 22 calls to Foswiki::Search::CORE:subst, avg 1µs/call | ||
1233 | Foswiki::Render::breakName( | ||||
1234 | $item->getParent(), $1 )/ges; | ||||
1235 | 22 | 34µs | $out =~ s/\$parent/$item->getParent()/ges; # spent 34µs making 22 calls to Foswiki::Search::CORE:subst, avg 2µs/call | ||
1236 | 22 | 32µs | $out =~ s/\$formname/$item->getFormName()/ges; # spent 32µs making 22 calls to Foswiki::Search::CORE:subst, avg 1µs/call | ||
1237 | 22 | 31µs | $out =~ s/\$count\((.*?\s*\.\*)\)/_countPattern( $text, $1 )/ges; # spent 31µs making 22 calls to Foswiki::Search::CORE:subst, avg 1µs/call | ||
1238 | |||||
1239 | # FIXME: Allow all regex characters but escape them | ||||
1240 | # Note: The RE requires a .* at the end of a pattern to avoid false positives | ||||
1241 | # in pattern matching | ||||
1242 | $out =~ | ||||
1243 | 22 | 31µs | s/\$pattern\((.*?\s*\.\*)\)/_extractPattern( $text, $1 )/ges; # spent 31µs making 22 calls to Foswiki::Search::CORE:subst, avg 1µs/call | ||
1244 | } | ||||
1245 | $out =~ s/\r?\n/$newLine/gos if ($newLine); | ||||
1246 | |||||
1247 | # If separator is not defined we default to \n | ||||
1248 | # We also add new line after last search result but before footer | ||||
1249 | # when separator is not defined for backwards compatibility | ||||
1250 | # per Item1773 / SearchSeparatorDefaultHeaderFooter | ||||
1251 | if ( !defined($separator) ) { | ||||
1252 | unless ( $noTotal && !$params->{formatdefined} ) { | ||||
1253 | $out =~ s/([^\n])$/$1\n/s; | ||||
1254 | } | ||||
1255 | } | ||||
1256 | } | ||||
1257 | |||||
1258 | #see http://foswiki.org/Tasks/Item2371 - needs unit test exploration | ||||
1259 | #the problem is that when I separated the formating from the searching, I set the format string to what is in the template, | ||||
1260 | #and thus here, format is always set. | ||||
1261 | # elsif ($noSummary) { | ||||
1262 | # #TODO: i think that means I've broken SEARCH{nosummary=on" with no format specified | ||||
1263 | # $out =~ s/%TEXTHEAD%//go; | ||||
1264 | # $out =~ s/ //go; | ||||
1265 | # } | ||||
1266 | # else { | ||||
1267 | # #SEARCH with no format and nonoise="off" or nosummary="off" | ||||
1268 | # #TODO: BROKEN, need to fix the meaning of nosummary and nonoise in SEARCH | ||||
1269 | # # regular search view | ||||
1270 | # $text = $info->{tom}->summariseText( '', $text ); | ||||
1271 | # $out =~ s/%TEXTHEAD%/$text/go; | ||||
1272 | # } | ||||
1273 | return $out; | ||||
1274 | } | ||||
1275 | |||||
1276 | =begin TML | ||||
1277 | |||||
1278 | ---++ StaticMethod displayFormField( $meta, $args ) -> $text | ||||
1279 | |||||
1280 | Parse the arguments to a $formfield specification and extract | ||||
1281 | the relevant formfield from the given meta data. | ||||
1282 | |||||
1283 | * =args= string containing name of form field | ||||
1284 | |||||
1285 | In addition to the name of a field =args= can be appended with a commas | ||||
1286 | followed by a string format (\d+)([,\s*]\.\.\.)?). This supports the formatted | ||||
1287 | search function $formfield and is used to shorten the returned string or a | ||||
1288 | hyphenated string. | ||||
1289 | |||||
1290 | =cut | ||||
1291 | |||||
1292 | sub displayFormField { | ||||
1293 | my ( $meta, $args ) = @_; | ||||
1294 | |||||
1295 | my $name = $args; | ||||
1296 | my $breakArgs = ''; | ||||
1297 | my @params = split( /\,\s*/, $args, 2 ); | ||||
1298 | if ( @params > 1 ) { | ||||
1299 | $name = $params[0] || ''; | ||||
1300 | $breakArgs = $params[1] || 1; | ||||
1301 | } | ||||
1302 | |||||
1303 | # SMELL: this is a *terrible* idea. Not only does it munge the result | ||||
1304 | # so it can only be used for display, it also munges it such that it | ||||
1305 | # can't be repaired by the options on %SEARCH. | ||||
1306 | return $meta->renderFormFieldForDisplay( $name, '$value', | ||||
1307 | { break => $breakArgs, protectdollar => 1, showhidden => 1 } ); | ||||
1308 | } | ||||
1309 | |||||
1310 | #my ($callback, $cbdata) = setup_callback(\%params, $baseWebObject); | ||||
1311 | sub setup_callback { | ||||
1312 | 15 | 58µs | my ( $params, $webObj ) = @_; | ||
1313 | |||||
1314 | my $callback = $params->{_callback}; | ||||
1315 | my $cbdata = $params->{_cbdata}; | ||||
1316 | |||||
1317 | #add in the rendering.. | ||||
1318 | 4 | 31µs | if ( defined( $params->{_callback} ) ) { | ||
1319 | # spent 1.50ms (949µs+550µs) within Foswiki::Search::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm:1327] which was called 44 times, avg 34µs/call:
# 22 times (469µs+342µs) by Foswiki::Search::formatResults at line 1015, avg 37µs/call
# 21 times (461µs+200µs) by Foswiki::Search::formatResults at line 903, avg 32µs/call
# once (20µs+8µs) by Foswiki::Search::formatResults at line 1072 | ||||
1320 | 264 | 1.00ms | my $cbdata = shift; | ||
1321 | my $text = shift; | ||||
1322 | my $oldcallback = $params->{_callback}; | ||||
1323 | |||||
1324 | $text = $webObj->renderTML($text) if defined($webObj); | ||||
1325 | 44 | 88µs | $text =~ s|</*nop/*>||goi; # remove <nop> tag # spent 88µs making 44 calls to Foswiki::Search::CORE:subst, avg 2µs/call | ||
1326 | 44 | 462µs | &$oldcallback( $cbdata, $text ); # spent 462µs making 44 calls to Foswiki::Users::TopicUserMapping::_collateGroups, avg 11µs/call | ||
1327 | }; | ||||
1328 | } | ||||
1329 | else { | ||||
1330 | $cbdata = $params->{_cbdata} = [] unless ( defined($cbdata) ); | ||||
1331 | $callback = \&_collate_to_list; | ||||
1332 | } | ||||
1333 | return ( $callback, $cbdata ); | ||||
1334 | } | ||||
1335 | |||||
1336 | # callback for search function to collate to list | ||||
1337 | sub _collate_to_list { | ||||
1338 | my $ref = shift; | ||||
1339 | |||||
1340 | push( @$ref, @_ ); | ||||
1341 | } | ||||
1342 | |||||
1343 | 1 | 5µs | 1; | ||
1344 | __END__ | ||||
sub Foswiki::Search::CORE:match; # opcode | |||||
# spent 4.32ms within Foswiki::Search::CORE:regcomp which was called 462 times, avg 9µs/call:
# 286 times (2.99ms+0s) by Foswiki::Search::formatResult at line 1169, avg 10µs/call
# 88 times (735µs+0s) by Foswiki::Search::formatResult at line 1161, avg 8µs/call
# 88 times (591µs+0s) by Foswiki::Search::formatResult at line 1192, avg 7µs/call | |||||
# spent 1.53ms within Foswiki::Search::CORE:subst which was called 867 times, avg 2µs/call:
# 286 times (579µs+0s) by Foswiki::Search::formatResult at line 1169, avg 2µs/call
# 88 times (146µs+0s) by Foswiki::Search::formatResult at line 1192, avg 2µs/call
# 88 times (140µs+0s) by Foswiki::Search::formatResult at line 1161, avg 2µs/call
# 44 times (88µs+0s) by Foswiki::Search::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm:1327] at line 1325, avg 2µs/call
# 22 times (48µs+0s) by Foswiki::Search::formatResult at line 1226, avg 2µs/call
# 22 times (42µs+0s) by Foswiki::Search::formatResults at line 939, avg 2µs/call
# 22 times (40µs+0s) by Foswiki::Search::formatResults at line 928, avg 2µs/call
# 22 times (39µs+0s) by Foswiki::Search::formatResult at line 1203, avg 2µs/call
# 22 times (38µs+0s) by Foswiki::Search::formatResults at line 934, avg 2µs/call
# 22 times (36µs+0s) by Foswiki::Search::formatResults at line 938, avg 2µs/call
# 22 times (34µs+0s) by Foswiki::Search::formatResult at line 1235, avg 2µs/call
# 22 times (33µs+0s) by Foswiki::Search::formatResult at line 1228, avg 2µs/call
# 22 times (32µs+0s) by Foswiki::Search::formatResult at line 1232, avg 1µs/call
# 22 times (32µs+0s) by Foswiki::Search::formatResult at line 1236, avg 1µs/call
# 22 times (31µs+0s) by Foswiki::Search::formatResult at line 1230, avg 1µs/call
# 22 times (31µs+0s) by Foswiki::Search::formatResult at line 1243, avg 1µs/call
# 22 times (31µs+0s) by Foswiki::Search::formatResult at line 1237, avg 1µs/call
# 22 times (30µs+0s) by Foswiki::Search::formatResults at line 935, avg 1µs/call
# 22 times (29µs+0s) by Foswiki::Search::formatResults at line 940, avg 1µs/call
# 22 times (28µs+0s) by Foswiki::Search::formatResults at line 933, avg 1µs/call
# once (4µs+0s) by Foswiki::Search::loadTemplates at line 486
# once (4µs+0s) by Foswiki::Search::searchWeb at line 314
# once (2µs+0s) by Foswiki::Search::formatResults at line 1058
# once (2µs+0s) by Foswiki::Search::loadTemplates at line 535
# once (1µs+0s) by Foswiki::Search::formatResults at line 1063
# once (1µs+0s) by Foswiki::Search::formatResults at line 1065
# once (1µs+0s) by Foswiki::Search::formatResults at line 1064
# once (1µs+0s) by Foswiki::Search::loadTemplates at line 536
# once (1µs+0s) by Foswiki::Search::formatResults at line 1068 | |||||
# spent 107µs within Foswiki::Search::CORE:substcont which was called 44 times, avg 2µs/call:
# 44 times (107µs+0s) by Foswiki::Search::formatResult at line 1169, avg 2µs/call |