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