Doxygen
Loading...
Searching...
No Matches
searchindex_js.cpp
Go to the documentation of this file.
1/******************************************************************************
2 *
3 * Copyright (C) 1997-2022 by Dimitri van Heesch.
4 *
5 * Permission to use, copy, modify, and distribute this software and its
6 * documentation under the terms of the GNU General Public License is hereby
7 * granted. No representations are made about the suitability of this software
8 * for any purpose. It is provided "as is" without express or implied warranty.
9 * See the GNU General Public License for more details.
10 *
11 * Documents produced by Doxygen are derivative works derived from the
12 * input used in their production; they are not affected by this license.
13 *
14 */
15
16// own header
17#include "searchindex_js.h"
18
19// standard includes
20#include <algorithm>
21#include <utility>
22
23// other includes
24#include "classdef.h"
25#include "classlist.h"
26#include "conceptdef.h"
27#include "docparser.h"
28#include "doxygen.h"
29#include "filename.h"
30#include "groupdef.h"
31#include "indexlist.h"
32#include "language.h"
33#include "membername.h"
34#include "message.h"
35#include "moduledef.h"
36#include "namespacedef.h"
37#include "pagedef.h"
38#include "portable.h"
39#include "resourcemgr.h"
40#include "section.h"
41#include "textstream.h"
42#include "threadpool.h"
43#include "util.h"
44
46{
47 if (std::holds_alternative<const Definition *>(info))
48 {
49 const Definition *def = std::get<const Definition *>(info);
51 title = type==Definition::TypeGroup ? parseCommentAsHtml(def,nullptr,toGroupDef(def)->groupTitle(),def->getDefFileName(),def->getDefLine()) :
52 type==Definition::TypePage ? parseCommentAsHtml(def,nullptr,toPageDef(def)->title(),def->getDefFileName(),def->getDefLine()) :
53 def->localName();
54 }
55 else if (std::holds_alternative<const SectionInfo *>(info))
56 {
57 const SectionInfo *si = std::get<const SectionInfo *>(info);
58 title = parseCommentAsHtml(si->definition(),nullptr,si->title(),si->fileName(),si->lineNr());
59 }
60 else
61 {
62 ASSERT(false);
63 }
64}
65
67{
68 TextStream t;
69
70 for (size_t i=0;i<word.length();i++)
71 {
72 char c = word.at(i);
73 if (static_cast<signed char>(c)<0 || isalnum(c))
74 {
75 t << word.at(i);
76 }
77 else // escape non-identifier characters
78 {
79 static const char *hex = "0123456789ABCDEF";
80 unsigned char uc = static_cast<unsigned char>(word.at(i));
81 t << '_';
82 t << hex[uc>>4];
83 t << hex[uc&0xF];
84 }
85 }
86
87 return convertUTF8ToLower(t.str());
88}
89
90//-------------------------------------------------------------------------------------------
91
92//! helper function to simplify the given title string, and fill a list of start positions
93//! for the start of each word in the simplified title string.
94static void splitSearchTokens(DString &title,SizeVector &indices)
95{
96 if (title.empty()) return;
97
98 // simplify title to contain only words with single space as separator
99 size_t di=0;
100 bool lastIsSpace=true;
101 for (size_t si=0; si<title.length(); si++)
102 {
103 char c = title.at(si);
104 if (c=='@' || c=='\\') // skip over special commands
105 {
106 title.at(di)=' ';
107 if (si<title.length()-1)
108 {
109 c = title.at(++si);
110 while (si<title.length() && (isId(c) || c==':')) c = title.at(++si);
111 --si;
112 }
113 }
114 else if (c=='<') // skip over html tags
115 {
116 if (si<title.length()-1)
117 {
118 for (size_t tsi = si; tsi<title.length(); ++tsi)
119 {
120 if (title.at(tsi)=='>')
121 {
122 si=tsi;
123 break;
124 }
125 }
126 }
127 }
128 else if (isId(c) || c==':') // add "word" character
129 {
130 title.at(di)=c;
131 di++;
132 lastIsSpace=false;
133 }
134 else if (!lastIsSpace) // add one separator as space
135 {
136 title.at(di)=' ';
137 di++;
138 lastIsSpace=true;
139 }
140 }
141 if (di>0 && title.at(di-1)==' ') di--; // strip trailing whitespace
142 title.resize(di);
143
144 // create a list of start positions within title for
145 // each unique word in order of appearance
146 size_t p=0,i=0;
147 while ((i=title.find(' ',p))!=DString::npos)
148 {
149 std::string word = title.mid(p,i-p).str();
150 indices.push_back(p);
151 p = i+1;
152 }
153 if (p<title.length())
154 {
155 std::string word = title.mid(p).str();
156 indices.push_back(p);
157 }
158}
159
160//-------------------------------------------------------------------------------------------
161
162#define SEARCH_INDEX_ALL 0
163#define SEARCH_INDEX_CLASSES 1
164#define SEARCH_INDEX_INTERFACES 2
165#define SEARCH_INDEX_STRUCTS 3
166#define SEARCH_INDEX_EXCEPTIONS 4
167#define SEARCH_INDEX_NAMESPACES 5
168#define SEARCH_INDEX_FILES 6
169#define SEARCH_INDEX_FUNCTIONS 7
170#define SEARCH_INDEX_VARIABLES 8
171#define SEARCH_INDEX_TYPEDEFS 9
172#define SEARCH_INDEX_SEQUENCES 10
173#define SEARCH_INDEX_DICTIONARIES 11
174#define SEARCH_INDEX_ENUMS 12
175#define SEARCH_INDEX_ENUMVALUES 13
176#define SEARCH_INDEX_PROPERTIES 14
177#define SEARCH_INDEX_EVENTS 15
178#define SEARCH_INDEX_RELATED 16
179#define SEARCH_INDEX_DEFINES 17
180#define SEARCH_INDEX_GROUPS 18
181#define SEARCH_INDEX_PAGES 19
182#define SEARCH_INDEX_CONCEPTS 20
183#define SEARCH_INDEX_MODULES 21
184
185static std::array<SearchIndexInfo,NUM_SEARCH_INDICES> g_searchIndexInfo =
186{ {
187 // index name getText symbolList
188 { /* SEARCH_INDEX_ALL */ "all" , []() { return theTranslator->trAll(); }, {} },
189 { /* SEARCH_INDEX_CLASSES */ "classes" , []() { return theTranslator->trClasses(); }, {} },
190 { /* SEARCH_INDEX_INTERFACES */ "interfaces" , []() { return theTranslator->trSliceInterfaces(); }, {} },
191 { /* SEARCH_INDEX_STRUCTS */ "structs" , []() { return theTranslator->trStructs(); }, {} },
192 { /* SEARCH_INDEX_EXCEPTIONS */ "exceptions" , []() { return theTranslator->trExceptions(); }, {} },
193 { /* SEARCH_INDEX_NAMESPACES */ "namespaces" , []() { return Config_getBool(OPTIMIZE_OUTPUT_SLICE) ?
195 theTranslator->trNamespace(true,false); }, {} },
196 { /* SEARCH_INDEX_FILES */ "files" , []() { return theTranslator->trFile(true,false); }, {} },
197 { /* SEARCH_INDEX_FUNCTIONS */ "functions" , []() { return Config_getBool(OPTIMIZE_OUTPUT_SLICE) ?
199 theTranslator->trFunctions(); }, {} },
200 { /* SEARCH_INDEX_VARIABLES */ "variables" , []() { return Config_getBool(OPTIMIZE_OUTPUT_SLICE) ?
202 theTranslator->trVariables(); }, {} },
203 { /* SEARCH_INDEX_TYPEDEFS */ "typedefs" , []() { return theTranslator->trTypedefs(); }, {} },
204 { /* SEARCH_INDEX_SEQUENCES */ "sequences" , []() { return theTranslator->trSequences(); }, {} },
205 { /* SEARCH_INDEX_DICTIONARIES */ "dictionaries", []() { return theTranslator->trDictionaries(); }, {} },
206 { /* SEARCH_INDEX_ENUMS */ "enums" , []() { return theTranslator->trEnumerations(); }, {} },
207 { /* SEARCH_INDEX_ENUMVALUES */ "enumvalues" , []() { return theTranslator->trEnumerationValues(); }, {} },
208 { /* SEARCH_INDEX_PROPERTIES */ "properties" , []() { return theTranslator->trProperties(); }, {} },
209 { /* SEARCH_INDEX_EVENTS */ "events" , []() { return theTranslator->trEvents(); }, {} },
210 { /* SEARCH_INDEX_RELATED */ "related" , []() { return theTranslator->trFriends(); }, {} },
211 { /* SEARCH_INDEX_DEFINES */ "defines" , []() { return theTranslator->trDefines(); }, {} },
212 { /* SEARCH_INDEX_GROUPS */ "groups" , []() { return theTranslator->trGroup(true,false); }, {} },
213 { /* SEARCH_INDEX_PAGES */ "pages" , []() { return theTranslator->trPage(true,false); }, {} },
214 { /* SEARCH_INDEX_CONCEPTS */ "concepts" , []() { return theTranslator->trConcept(true,false); }, {} },
215 { /* SEARCH_INDEX_MODULES */ "modules" , []() { return theTranslator->trModule(true,false); }, {} }
216} };
217
218static void addMemberToSearchIndex(const MemberDef *md)
219{
220 bool hideFriendCompounds = Config_getBool(HIDE_FRIEND_COMPOUNDS);
221 bool isLinkable = md->isLinkable();
222 const ClassDef *cd=nullptr;
223 const NamespaceDef *nd=nullptr;
224 const FileDef *fd=nullptr;
225 const GroupDef *gd=nullptr;
226 if (isLinkable &&
227 (
228 ((cd=md->getClassDef()) && cd->isLinkable() && !cd->isImplicitTemplateInstance()) ||
229 ((gd=md->getGroupDef()) && gd->isLinkable())
230 )
231 )
232 {
233 const DString &n = md->name();
234 if (!n.empty())
235 {
236 bool isFriendToHide = hideFriendCompounds && isTypeAClassFriend(md->typeString());
237 if (!(md->isFriend() && isFriendToHide))
238 {
240 }
241 if (md->isFunction() || md->isSlot() || md->isSignal())
242 {
244 }
245 else if (md->isVariable())
246 {
248 }
249 else if (md->isSequence())
250 {
252 }
253 else if (md->isDictionary())
254 {
256 }
257 else if (md->isTypedef())
258 {
260 }
261 else if (md->isEnumerate())
262 {
264 }
265 else if (md->isEnumValue())
266 {
268 }
269 else if (md->isProperty())
270 {
272 }
273 else if (md->isEvent())
274 {
276 }
277 else if (md->isRelated() || md->isForeign() ||
278 (md->isFriend() && !isFriendToHide))
279 {
281 }
282 }
283 }
284 else if (isLinkable &&
285 (((nd=md->getNamespaceDef()) && nd->isLinkable()) ||
286 ((fd=md->getFileDef()) && fd->isLinkable())
287 )
288 )
289 {
290 const DString &n = md->name();
291 if (!n.empty())
292 {
294
295 if (md->isFunction())
296 {
298 }
299 else if (md->isVariable())
300 {
302 }
303 else if (md->isSequence())
304 {
306 }
307 else if (md->isDictionary())
308 {
310 }
311 else if (md->isTypedef())
312 {
314 }
315 else if (md->isEnumerate())
316 {
318 }
319 else if (md->isEnumValue())
320 {
322 }
323 else if (md->isDefine())
324 {
326 }
327 }
328 }
329}
330
331//---------------------------------------------------------------------------------------------
332
334{
335 // index classes
336 for (const auto &cd : *Doxygen::classLinkedMap)
337 {
338 if (cd->isLinkable())
339 {
340 DString n = cd->localName();
342 if (Config_getBool(OPTIMIZE_OUTPUT_SLICE))
343 {
344 if (cd->compoundType()==ClassDef::Interface)
345 {
347 }
348 else if (cd->compoundType()==ClassDef::Struct)
349 {
351 }
352 else if (cd->compoundType()==ClassDef::Exception)
353 {
355 }
356 else // cd->compoundType()==ClassDef::Class
357 {
359 }
360 }
361 else // non slice optimization: group all types under classes
362 {
364 }
365 }
366 }
367
368 // index namespaces
369 for (const auto &nd : *Doxygen::namespaceLinkedMap)
370 {
371 if (nd->isLinkable())
372 {
373 DString n = nd->name();
376 }
377 }
378
379 // index concepts
380 for (const auto &cd : *Doxygen::conceptLinkedMap)
381 {
382 if (cd->isLinkable())
383 {
384 DString n = cd->localName();
387 }
388 }
389
390 // index modules
391 for (const auto &mod : ModuleManager::instance().modules())
392 {
393 if (mod->isLinkable() && mod->isPrimaryInterface())
394 {
395 DString n = mod->name();
398 }
399 }
400
401 // index files
402 for (const auto &fn : *Doxygen::inputNameLinkedMap)
403 {
404 for (const auto &fd : *fn)
405 {
406 DString n = fd->name();
407 if (fd->isLinkable())
408 {
411 }
412 }
413 }
414
415 // index class members
416 {
417 // for each member name
418 for (const auto &mn : *Doxygen::memberNameLinkedMap)
419 {
420 // for each member definition
421 for (const auto &md : *mn)
422 {
423 addMemberToSearchIndex(md.get());
424 }
425 }
426 }
427
428 // index file/namespace members
429 {
430 // for each member name
431 for (const auto &mn : *Doxygen::functionNameLinkedMap)
432 {
433 // for each member definition
434 for (const auto &md : *mn)
435 {
436 addMemberToSearchIndex(md.get());
437 }
438 }
439 }
440
441 // index groups
442 for (const auto &gd : *Doxygen::groupLinkedMap)
443 {
444 if (gd->isLinkable())
445 {
446 DString title(filterTitle(gd->groupTitle()).str());
447 SizeVector tokenIndices;
448 splitSearchTokens(title,tokenIndices);
449 for (size_t index : tokenIndices)
450 {
451 g_searchIndexInfo[SEARCH_INDEX_ALL].add(SearchTerm(title.mid(index),gd.get()));
452 g_searchIndexInfo[SEARCH_INDEX_GROUPS].add(SearchTerm(title.mid(index),gd.get()));
453 }
454 }
455 }
456
457 // index pages
458 for (const auto &pd : *Doxygen::pageLinkedMap)
459 {
460 if (pd->isLinkable())
461 {
462 DString title(filterTitle(pd->title()).str());
463 SizeVector tokenIndices;
464 splitSearchTokens(title,tokenIndices);
465 for (size_t index : tokenIndices)
466 {
467 g_searchIndexInfo[SEARCH_INDEX_ALL].add(SearchTerm(title.mid(index),pd.get()));
468 g_searchIndexInfo[SEARCH_INDEX_PAGES].add(SearchTerm(title.mid(index),pd.get()));
469 }
470 }
471 }
472
473 // main page
475 {
476 DString title(filterTitle(Doxygen::mainPage->title()).str());
477 SizeVector tokenIndices;
478 splitSearchTokens(title,tokenIndices);
479 for (size_t index : tokenIndices)
480 {
483 }
484 }
485
486 // sections
487 const auto &sm = SectionManager::instance();
488 for (const auto &sectionInfo : sm)
489 {
490 if (sectionInfo->level()>0) // level 0 is for page titles
491 {
492 DString title = filterTitle(sectionInfo->title());
493 SizeVector tokenIndices;
494 splitSearchTokens(title,tokenIndices);
495 //printf("split(%s)=(%s) %zu\n",qPrint(sectionInfo->title()),qPrint(title),tokenIndices.size());
496 for (size_t index : tokenIndices)
497 {
498 g_searchIndexInfo[SEARCH_INDEX_ALL].add(SearchTerm(title.mid(index),sectionInfo.get()));
499 g_searchIndexInfo[SEARCH_INDEX_PAGES].add(SearchTerm(title.mid(index),sectionInfo.get()));
500 }
501 }
502 }
503
504 // sort all lists
505 for (auto &sii : g_searchIndexInfo) // for each index
506 {
507 for (auto &[name,symList] : sii.symbolMap) // for each symbol in the index
508 {
509 // sort the symbols (first on search term, and then on full name)
510 //
511 // `std::stable_sort` is used here due to reproducibility issues
512 // on key collisions
513 // https://github.com/doxygen/doxygen/issues/10445
514 std::stable_sort(symList.begin(),
515 symList.end(),
516 [](const auto &t1,const auto &t2)
517 {
518 int eq = dstricmp_sort(t1.word,t2.word); // search term first
519 return eq==0 ? dstricmp_sort(t1.title,t2.title)<0 : eq<0; // then full title
520 });
521 }
522 }
523}
524
525static void writeJavascriptSearchData(const DString &searchDirName)
526{
527 std::ofstream t = Portable::openOutputStream(searchDirName+"/searchdata.js");
528 if (t.is_open())
529 {
530 t << "var indexSectionsWithContent =\n";
531 t << "{\n";
532 int j=0;
533 for (const auto &sii : g_searchIndexInfo)
534 {
535 if (!sii.symbolMap.empty())
536 {
537 if (j>0) t << ",\n";
538 t << " " << j << ": \"";
539
540 std::string previous_letter; // start with value that does not exist in the map
541 for (const auto &[letter,list] : sii.symbolMap)
542 {
543 if (letter != previous_letter)
544 {
545 if ( letter == "\"" ) t << "\\"; // add escape for backslash
546 t << letter;
547 previous_letter = letter;
548 }
549 }
550 t << "\"";
551 j++;
552 }
553 }
554 if (j>0) t << "\n";
555 t << "};\n\n";
556 t << "var indexSectionNames =\n";
557 t << "{\n";
558 j=0;
559 for (const auto &sii : g_searchIndexInfo)
560 {
561 if (!sii.symbolMap.empty())
562 {
563 if (j>0) t << ",\n";
564 t << " " << j << ": \"" << convertToJSString(sii.name,true,false) << "\"";
565 j++;
566 }
567 }
568 if (j>0) t << "\n";
569 t << "};\n\n";
570 t << "var indexSectionLabels =\n";
571 t << "{\n";
572 j=0;
573 for (const auto &sii : g_searchIndexInfo)
574 {
575 if (!sii.symbolMap.empty())
576 {
577 if (j>0) t << ",\n";
578 t << " " << j << ": \"" << convertToJSString(convertToXML(sii.getText()),true,false) << "\"";
579 j++;
580 }
581 }
582 if (j>0) t << "\n";
583 t << "};\n\n";
584 }
585}
586
587static void writeJavasScriptSearchDataPage(const DString &baseName,const DString &dataFileName,const SearchIndexList &list)
588{
589 auto isDef = [](const SearchTerm::LinkInfo &info)
590 {
591 return std::holds_alternative<const Definition *>(info);
592 };
593 auto getDef = [&isDef](const SearchTerm::LinkInfo &info)
594 {
595 return isDef(info) ? std::get<const Definition *>(info) : nullptr;
596 };
597 auto isSection = [](const SearchTerm::LinkInfo &info)
598 {
599 return std::holds_alternative<const SectionInfo *>(info);
600 };
601 auto getSection = [&isSection](const SearchTerm::LinkInfo &info)
602 {
603 return isSection(info) ? std::get<const SectionInfo *>(info) : nullptr;
604 };
605
606 int cnt = 0;
607 std::ofstream ti = Portable::openOutputStream(dataFileName);
608 if (!ti.is_open())
609 {
610 err("Failed to open file '{}' for writing...\n",dataFileName);
611 return;
612 }
613
614 ti << "var searchData=\n";
615 // format
616 // searchData[] = array of items
617 // searchData[x][0] = id
618 // searchData[x][1] = [ name + child1 + child2 + .. ]
619 // searchData[x][1][0] = name as shown
620 // searchData[x][1][y+1] = info for child y
621 // searchData[x][1][y+1][0] = url
622 // searchData[x][1][y+1][1] = 1 => target="_parent"
623 // searchData[x][1][y+1][1] = 0 => target="_blank"
624 // searchData[x][1][y+1][2] = scope
625
626 ti << "[\n";
627 bool firstEntry=true;
628
629 int childCount=0;
630 DString lastWord;
631 const Definition *prevScope = nullptr;
632 for (auto it = list.begin(); it!=list.end();)
633 {
634 const SearchTerm &term = *it;
635 const SearchTerm::LinkInfo info = term.info;
636 const Definition *d = getDef(info);
637 const SectionInfo *si = getSection(info);
638 ASSERT(d || si); // either d or si should be valid
639 DString word = term.word;
640 DString id = term.termEncoded();
641 ++it;
642 const Definition *scope = d ? d->getOuterScope() : nullptr;
643 const SearchTerm::LinkInfo next = it!=list.end() ? it->info : SearchTerm::LinkInfo();
644 const Definition *nextScope = isDef(next) ? getDef(next)->getOuterScope() : nullptr;
645 const MemberDef *md = toMemberDef(d);
646 DString anchor = d ? d->anchor() : si ? si->label() : DString();
647
648 if (word!=lastWord) // this item has a different search word
649 {
650 if (!firstEntry)
651 {
652 ti << "]]]";
653 ti << ",\n";
654 }
655 firstEntry=false;
656 ti << " ['" << id << "_" << cnt++ << "',['";
657 if (next==SearchTerm::LinkInfo() || it->word!=word) // unique result, show title
658 {
659 ti << convertToJSString(convertToXML(term.title),true,true);
660 }
661 else // multiple results, show matching word only, expanded list will show title
662 {
663 ti << convertToJSString(convertToXML(term.word),true,true);
664 }
665 ti << "',[";
666 childCount=0;
667 prevScope=nullptr;
668 }
669
670 if (childCount>0)
671 {
672 ti << "],[";
673 }
674 DString fn = d ? d->getOutputFileBase() : si ? si->fileName() : DString();
675 DString ref = d ? d->getReference() : si ? si->ref() : DString();
677 DString extRef = externalRef("../",ref)+fn;
678 if (!anchor.empty())
679 {
680 extRef+="#"+anchor;
681 }
682 ti << "'" << convertToJSString(extRef,true,true) << "',";
683
684 bool extLinksInWindow = Config_getBool(EXT_LINKS_IN_WINDOW);
685 if (!extLinksInWindow || ref.empty())
686 {
687 ti << "1,";
688 }
689 else
690 {
691 ti << "0,";
692 }
693
694 if (lastWord!=word && (next==SearchTerm::LinkInfo() || it->word!=word)) // unique search result
695 {
696 if (d && d->getOuterScope()!=Doxygen::globalScope)
697 {
698 ti << "'" << convertToJSString(convertToXML(d->getOuterScope()->name()),true,true) << "'";
699 }
700 else if (md)
701 {
702 const FileDef *fd = md->getBodyDef();
703 if (fd==nullptr) fd = md->getFileDef();
704 if (fd)
705 {
706 ti << "'" << convertToJSString(convertToXML(fd->localName()),true,true) << "'";
707 }
708 }
709 else
710 {
711 ti << "''";
712 }
713 }
714 else // multiple entries with the same name
715 {
716 bool found=false;
717 bool overloadedFunction = ((prevScope!=nullptr && scope==prevScope) || (scope && scope==nextScope)) &&
718 md && md->isCallable();
720 if (md) prefix=convertToXML(md->localName());
721 if (overloadedFunction) // overloaded member function
722 {
724 // show argument list to disambiguate overloaded functions
725 }
726 else if (md && md->isCallable()) // unique member function
727 {
728 prefix+="()"; // only to show it is a callable symbol
729 }
730 DString name;
731 if (d)
732 {
733 switch (d->definitionType())
734 {
735 case Definition::TypeClass: name = convertToXML((toClassDef(d))->displayName()); found=true; break;
736 case Definition::TypeNamespace: name = convertToXML((toNamespaceDef(d))->displayName()); found=true; break;
737 case Definition::TypeModule: name = convertToXML(d->name()+" "+theTranslator->trModule(false,true)); found=true; break;
738 case Definition::TypePage: name = convertToXML(filterTitle(toPageDef(d)->title())); found=true; break;
739 case Definition::TypeGroup: name = convertToXML(filterTitle(toGroupDef(d)->groupTitle())); found=true; break;
740 default:
741 if (scope==nullptr || scope==Doxygen::globalScope) // in global scope
742 {
743 if (md)
744 {
745 const FileDef *fd = md->getBodyDef();
746 if (fd==nullptr) fd = md->resolveAlias()->getFileDef();
747 if (fd)
748 {
749 if (!prefix.empty()) prefix+=":&#160;";
750 name = prefix + convertToXML(fd->localName());
751 found = true;
752 }
753 }
754 }
755 else if (md && (md->resolveAlias()->getClassDef() || md->resolveAlias()->getNamespaceDef()))
756 // member in class or namespace scope
757 {
758 SrcLangExt lang = md->getLanguage();
760 name = convertToXML(d->getOuterScope()->qualifiedName()) + sep + prefix;
761 found = true;
762 }
763 else if (scope) // some thing else? -> show scope
764 {
765 name = prefix + convertToXML(scope->name());
766 found = true;
767 }
768 break;
769 }
770 }
771 else if (si)
772 {
773 name = parseCommentAsHtml(si->definition(),nullptr,si->title(),si->fileName(),si->lineNr());
774 name = convertToXML(name);
775 found = true;
776 }
777 if (!found) // fallback
778 {
779 name = prefix + "("+theTranslator->trGlobalNamespace()+")";
780 }
781
782 ti << "'" << convertToJSString(name,true,true) << "'";
783
784 prevScope = scope;
785 childCount++;
786 }
787 lastWord = word;
788 }
789 if (!firstEntry)
790 {
791 ti << "]]]\n";
792 }
793 ti << "];\n";
794 Doxygen::indexList->addStyleSheetFile(("search/"+baseName+".js").data());
795}
796
797
799{
800 // write index files
801 DString searchDirName = Config_getString(HTML_OUTPUT)+"/search";
802
803 std::size_t numThreads = static_cast<std::size_t>(Config_getInt(NUM_PROC_THREADS));
804 if (numThreads>1) // multi threaded version
805 {
806 ThreadPool threadPool(numThreads);
807 std::vector< std::future<int> > results;
808 for (auto &sii : g_searchIndexInfo)
809 {
810 int p=0;
811 for (const auto &[letter,symList] : sii.symbolMap)
812 {
813 DString baseName;
814 baseName.sprintf("%s_%x",sii.name.data(),p);
815 DString dataFileName = searchDirName + "/"+baseName+".js";
816 auto &list = symList;
817 auto processFile = [p,baseName,dataFileName,&list]()
818 {
819 writeJavasScriptSearchDataPage(baseName,dataFileName,list);
820 return p;
821 };
822 results.emplace_back(threadPool.queue(processFile));
823 p++;
824 }
825 }
826 // wait for the results
827 for (auto &f : results) f.get();
828 }
829 else // single threaded version
830 {
831 for (auto &sii : g_searchIndexInfo)
832 {
833 int p=0;
834 for (const auto &[letter,symList] : sii.symbolMap)
835 {
836 DString baseName;
837 baseName.sprintf("%s_%x",sii.name.data(),p);
838 DString dataFileName = searchDirName + "/"+baseName+".js";
839 writeJavasScriptSearchDataPage(baseName,dataFileName,symList);
840 p++;
841 }
842 }
843 }
844
845 writeJavascriptSearchData(searchDirName);
846 auto &mgr = ResourceMgr::instance();
847 {
848 std::ofstream fn = Portable::openOutputStream(searchDirName+"/search.js");
849 if (fn.is_open())
850 {
851 TextStream t(&fn);
852 t << substitute(mgr.getAsString("search.js"),"$PROJECTID",getProjectId());
853 }
854 }
855
856 Doxygen::indexList->addStyleSheetFile("search/searchdata.js");
857 Doxygen::indexList->addStyleSheetFile("search/search.js");
858}
859
860//--------------------------------------------------------------------------------------
861
863{
864 std::string letter = convertUTF8ToLower(getUTF8CharAt(term.word.str(),0));
865 auto &list = symbolMap[letter]; // creates a new entry if not found
866 list.push_back(term);
867}
868
869const std::array<SearchIndexInfo,NUM_SEARCH_INDICES> &getSearchIndices()
870{
871 return g_searchIndexInfo;
872}
873
constexpr auto prefix
Definition anchor.cpp:47
A abstract class representing of a compound symbol.
Definition classdef.h:100
virtual bool isImplicitTemplateInstance() const =0
@ Interface
Definition classdef.h:108
@ Exception
Definition classdef.h:111
A String class for use with Doxygen wrapping std::string and adding some additional functionality off...
Definition dstring.h:84
void resize(size_t newlen)
Definition dstring.h:209
DString mid(size_t index, size_t len=npos) const
Definition dstring.h:318
bool empty() const
Returns true iff the string is empty (std::string compatible alias for isEmpty()).
Definition dstring.h:148
static constexpr size_t npos
value used to indicate 'not found' or 'to the end of the string', matching std::string::npos
Definition dstring.h:178
char & at(size_t i)
Returns a reference to the character at index i.
Definition dstring.h:686
size_t find(char c, size_t pos=0) const
Definition dstring.h:239
DString & sprintf(const char *format,...)
Definition dstring.cpp:34
const std::string & str() const
Definition dstring.h:645
size_t length() const
Returns the length of the string, not counting the 0-terminator.
Definition dstring.h:151
The common base class of all entity definitions found in the sources.
Definition definition.h:77
virtual SrcLangExt getLanguage() const =0
Returns the programming language this definition was written in.
virtual DString getDefFileName() const =0
virtual bool isLinkable() const =0
virtual int getDefLine() const =0
virtual DefType definitionType() const =0
virtual const DString & name() const =0
virtual const DString & localName() const =0
virtual const FileDef * getBodyDef() const =0
virtual DString qualifiedName() const =0
virtual DString anchor() const =0
virtual DString getReference() const =0
virtual Definition * getOuterScope() const =0
virtual DString getOutputFileBase() const =0
static NamespaceLinkedMap * namespaceLinkedMap
Definition doxygen.h:108
static ConceptLinkedMap * conceptLinkedMap
Definition doxygen.h:90
static std::unique_ptr< PageDef > mainPage
Definition doxygen.h:93
static FileNameLinkedMap * inputNameLinkedMap
Definition doxygen.h:97
static ClassLinkedMap * classLinkedMap
Definition doxygen.h:88
static MemberNameLinkedMap * functionNameLinkedMap
Definition doxygen.h:105
static NamespaceDefMutable * globalScope
Definition doxygen.h:114
static IndexList * indexList
Definition doxygen.h:125
static PageLinkedMap * pageLinkedMap
Definition doxygen.h:92
static MemberNameLinkedMap * memberNameLinkedMap
Definition doxygen.h:104
static GroupLinkedMap * groupLinkedMap
Definition doxygen.h:107
A model of a file symbol.
Definition filedef.h:97
A model of a group of symbols.
Definition groupdef.h:48
void addStyleSheetFile(const DString &name)
Definition indexlist.h:127
A model of a class/file/namespace member symbol.
Definition memberdef.h:45
virtual bool isSignal() const =0
virtual bool isFriend() const =0
virtual DString argsString() const =0
virtual bool isForeign() const =0
virtual bool isRelated() const =0
virtual bool isSequence() const =0
virtual const ClassDef * getClassDef() const =0
virtual GroupDef * getGroupDef()=0
virtual bool isTypedef() const =0
virtual bool isSlot() const =0
virtual const FileDef * getFileDef() const =0
virtual bool isEvent() const =0
virtual bool isFunction() const =0
virtual bool isDictionary() const =0
virtual MemberDef * resolveAlias()=0
virtual bool isDefine() const =0
virtual const NamespaceDef * getNamespaceDef() const =0
virtual bool isEnumerate() const =0
virtual bool isVariable() const =0
virtual DString typeString() const =0
virtual bool isCallable() const =0
virtual bool isEnumValue() const =0
virtual bool isProperty() const =0
static ModuleManager & instance()
An abstract interface of a namespace symbol.
static ResourceMgr & instance()
Returns the one and only instance of this class.
class that provide information about a section.
Definition section.h:58
DString fileName() const
Definition section.h:74
Definition * definition() const
Definition section.h:77
int lineNr() const
Definition section.h:73
DString title() const
Definition section.h:70
DString ref() const
Definition section.h:72
DString label() const
Definition section.h:69
static SectionManager & instance()
returns a reference to the singleton
Definition section.h:179
Text streaming class that buffers data.
Definition textstream.h:36
std::string str() const
Return the contents of the buffer as a std::string object.
Definition textstream.h:232
Class managing a pool of worker threads.
Definition threadpool.h:48
auto queue(F &&f, Args &&... args) -> std::future< decltype(f(args...))>
Queue the callable function f for the threads to execute.
Definition threadpool.h:77
virtual DString trTypedefs()=0
virtual DString trExceptions()=0
virtual DString trEnumerations()=0
virtual DString trClasses()=0
virtual DString trGroup(bool first_capital, bool singular)=0
virtual DString trNamespace(bool first_capital, bool singular)=0
virtual DString trStructs()=0
virtual DString trSequences()=0
virtual DString trFunctions()=0
virtual DString trFriends()=0
virtual DString trOperations()=0
virtual DString trGlobalNamespace()=0
virtual DString trModules()=0
virtual DString trDefines()=0
virtual DString trModule(bool first_capital, bool singular)=0
virtual DString trProperties()=0
virtual DString trConcept(bool first_capital, bool singular)=0
virtual DString trSliceInterfaces()=0
virtual DString trAll()=0
virtual DString trVariables()=0
virtual DString trEnumerationValues()=0
virtual DString trPage(bool first_capital, bool singular)=0
virtual DString trFile(bool first_capital, bool singular)=0
virtual DString trConstants()=0
virtual DString trEvents()=0
virtual DString trDictionaries()=0
ClassDef * toClassDef(Definition *d)
#define Config_getInt(name)
Definition config.h:34
#define Config_getBool(name)
Definition config.h:33
#define Config_getString(name)
Definition config.h:32
std::vector< size_t > SizeVector
Definition containers.h:39
DString parseCommentAsHtml(const Definition *scope, const MemberDef *member, const DString &doc, const DString &fileName, int lineNr)
DString substitute(const DString &s, const DString &src, const DString &dst)
substitute all occurrences of src in s by dst
Definition dstring.cpp:485
bool isId(char c)
Returns true if c is a valid character for an identifier.
Definition dstring.h:895
GroupDef * toGroupDef(Definition *d)
Translator * theTranslator
Definition language.cpp:76
MemberDef * toMemberDef(Definition *d)
#define err(fmt,...)
Definition message.h:127
#define ASSERT(x)
Definition message.h:142
#define term(fmt,...)
Definition message.h:137
std::ofstream openOutputStream(const DString &name, bool append=false)
Definition portable.cpp:681
NamespaceDef * toNamespaceDef(Definition *d)
PageDef * toPageDef(Definition *d)
Definition pagedef.cpp:656
Portable versions of functions that are platform dependent.
static void addMemberToSearchIndex(const MemberDef *md)
#define SEARCH_INDEX_TYPEDEFS
#define SEARCH_INDEX_STRUCTS
static void writeJavascriptSearchData(const DString &searchDirName)
#define SEARCH_INDEX_NAMESPACES
void createJavaScriptSearchIndex()
#define SEARCH_INDEX_CONCEPTS
#define SEARCH_INDEX_EVENTS
static std::array< SearchIndexInfo, NUM_SEARCH_INDICES > g_searchIndexInfo
#define SEARCH_INDEX_DEFINES
#define SEARCH_INDEX_ENUMS
#define SEARCH_INDEX_FILES
#define SEARCH_INDEX_DICTIONARIES
#define SEARCH_INDEX_PAGES
#define SEARCH_INDEX_ALL
#define SEARCH_INDEX_GROUPS
#define SEARCH_INDEX_INTERFACES
static void writeJavasScriptSearchDataPage(const DString &baseName, const DString &dataFileName, const SearchIndexList &list)
const std::array< SearchIndexInfo, NUM_SEARCH_INDICES > & getSearchIndices()
#define SEARCH_INDEX_SEQUENCES
#define SEARCH_INDEX_PROPERTIES
#define SEARCH_INDEX_ENUMVALUES
static void splitSearchTokens(DString &title, SizeVector &indices)
#define SEARCH_INDEX_FUNCTIONS
#define SEARCH_INDEX_VARIABLES
#define SEARCH_INDEX_MODULES
#define SEARCH_INDEX_CLASSES
#define SEARCH_INDEX_RELATED
void writeJavaScriptSearchIndex()
#define SEARCH_INDEX_EXCEPTIONS
Javascript based search engine.
std::vector< SearchTerm > SearchIndexList
List of search terms.
void add(const SearchTerm &term)
SearchIndexMap symbolMap
Searchable term.
DString word
lower case word that is indexed (e.g. name of a symbol, or word from a title)
std::variant< std::monostate, const Definition *, const SectionInfo * > LinkInfo
LinkInfo info
definition to link to
DString title
title to show in the output for this search result
DString termEncoded() const
encoded version of the search term
bool isTypeAClassFriend(const DString &type)
Definition types.h:920
SrcLangExt
Definition types.h:207
std::string convertUTF8ToLower(const std::string &input)
Converts the input string into a lower case version, also taking into account non-ASCII characters th...
Definition utf8.cpp:191
std::string getUTF8CharAt(const std::string &input, size_t pos)
Returns the UTF8 character found at byte position pos in the input string.
Definition utf8.cpp:131
DString filterTitle(const DString &title)
Definition util.cpp:4454
DString getProjectId()
Definition util.cpp:5270
DString convertToJSString(const DString &s, bool keepEntities, bool singleQuotes)
Definition util.cpp:3351
void addHtmlExtensionIfMissing(DString &fName)
Definition util.cpp:3931
DString convertToXML(const DString &s, bool keepEntities, const bool citeEntry)
Definition util.cpp:3232
DString getLanguageSpecificSeparator(SrcLangExt lang, bool classScope)
Definition util.cpp:4629
DString externalRef(const DString &relPath, const DString &ref)
Definition util.cpp:4538
A bunch of utility functions.