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