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