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