Improved Doxygen documentation and search Whether you are brows­ing Mag­num docs or use Doxy­gen for your own C++ doc­u­men­ta­tion, there’s al­ways a way to im­prove your work­flow. This ar­ti­cle presents the most re­cent ad­di­tions to the m.css Doxy­gen theme.

Update: Jan 12, 2019 Sup­port for EXTRACT_PRIV_VIRTUAL from doxy­gen/doxy­gen#6729 has been merged to Doxy­gen mas­ter (the op­tion was named EXTRACT_PRIVATE_VIRTUAL in the orig­i­nal patch); a fix for #include in­for­ma­tion is now in­te­grat­ed in doxy­gen/doxy­gen@7f40e48 (for­mer­ly doxy­gen/doxy­gen#6722).

A year ago I switched Mag­num docs to a theme writ­ten en­tire­ly from scratch, adding a nev­er-be­fore-seen search func­tion­al­i­ty a while lat­er. As the say­ing goes, eat­ing one’s own dog food is al­ways a good way to find ways to im­prove it, so dur­ing the whole year I col­lect­ed var­i­ous en­hance­ment ideas and not­ed rough cor­ners that need more pol­ish­ing, not to men­tion I re­ceived great feed­back from all the hap­py de­vel­op­ers that start­ed us­ing the theme for their own projects or were mere­ly the users of it through Mag­num doc­u­men­ta­tion.

Show­ing in­clude in­for­ma­tion for all the things A long-await­ed — and I would say al­so the most im­por­tant — ad­di­tion is in­for­ma­tion about what to #include to get giv­en sym­bol. But wait, that’s not all! While stock Doxy­gen shows in­clude paths on­ly for class­es — which made sense for clas­sic OOP-heavy code­bas­es — it cer­tain­ly doesn’t help much in Mag­num, which has a lot of func­tion­al­i­ty di­rect­ly in­side names­paces. While I’m try­ing hard to have the sym­bol ↔ file map­ping as in­tu­itive as pos­si­ble, it’s not al­ways clear and can be a lot of strug­gle es­pe­cial­ly for new­com­ers. So I went one step fur­ther and the doc­u­men­ta­tion now shows #include in­for­ma­tion not on­ly for class­es, but al­so for names­paces (in case they are ful­ly con­tained in a sin­gle head­er, such as An­i­ma­tion::Eas­ing), for free func­tions, type­defs, vari­ables and enums. That makes a big dif­fer­ence es­pe­cial­ly in large names­paces such as Math or GL. Im­ple­ment­ing this fea­ture un­cov­ered a Doxy­gen bug, so if you plan to use this fea­ture on your code­base, make sure to have a ver­sion with doxy­gen/doxy­gen@7f40e48 (for­mer­ly doxy­gen/doxy­gen#6722) in­clud­ed.

Pars­ing ad­di­tion­al func­tion at­trib­utes The theme was al­ready han­dling ex­tra at­tributes like delete d and default ed func­tions and noexcept — which Doxy­gen is not rec­og­niz­ing at all, if I re­mem­ber cor­rect­ly. To com­plete this, now al­so override , final and con­di­tion­al noexcept are parsed and shown. Be­sides that, final is rec­og­nized al­so for class­es, if you’d ev­er need that, and a few bugs re­lat­ed to pars­ing of those at­tributes were fixed. You can see these in ac­tion for ex­am­ple in Con­tain­ers::Op­tion­al.

Sup­port for doc­u­ment­ing pri­vate vir­tu­al func­tions The clas­sic ar­ti­cle about Vir­tu­al­i­ty by Herb Sut­ter sug­gests that a class has nev­er any pub­lic virtual func­tions, but rather a non-vir­tu­al pub­lic in­ter­face and all vir­tu­al in­ter­faces pri­vate. That makes the in­ter­face de­sign much more flex­i­ble and you don’t run in­to weird is­sues with co­vari­ant re­turn types. Mag­num fol­lows this rule since the very be­gin­ning in its ap­pli­ca­tion class­es (such as Plat­form::Sdl2Ap­pli­ca­tion) and all plug­in in­ter­faces like Trade::Ab­strac­tIm­porter, but un­til now Doxy­gen was not re­al­ly able to show doc­u­ment­ed pri­vate func­tions. To work around that, the pri­vate vir­tu­al func­tions used to be shown as protected , which was mis­lead­ing. Well, not any­more! Doxygen support If you want to use this fea­ture for your code­base, first make sure you have a build with doxy­gen/doxy­gen#6729 in­clud­ed. Then en­able EXTRACT_PRIV_VIRTUAL in your Doxyfile (it’s dis­abled by de­fault).

Im­proved or­der­ing for search re­sults The ini­tial search im­ple­men­ta­tion as ex­plained in this ar­ti­cle was pick­ing up the re­sults in what­ev­er or­der the search da­ta had them in. This was al­ready mil­lion times bet­ter and faster than the clas­sic Doxy­gen search im­ple­men­ta­tion, but lat­er I re­al­ized it could be eas­i­ly im­proved to or­der the re­sults in a more use­ful way — in par­tic­u­lar pre­fer­ring class­es and names­paces over func­tions and tuck­ing away dep­re­cat­ed and delete d func­tion­al­i­ty, since you’re far less like­ly to need doc­u­men­ta­tion for these: Search­ing for GL::Buf­fer be­fore … and af­ter For­tu­nate­ly, due to the way the search is im­ple­ment­ed, this was on­ly a mat­ter of sort­ing the re­sults while build­ing the search da­ta, it re­quired no com­plex al­go­rithm changes on the client side.

Au­to­com­ple­tion in the search field Be­sides the above, with fre­quent use it al­so be­came ap­par­ent that hav­ing to type long parts of sym­bol names to nar­row down the re­sults is … an­noy­ing. Again, a so­lu­tion was rather sim­ple to im­ple­ment, mak­ing use of a prop­er­ty of the Trie search struc­ture — it col­lects char­ac­ters un­til the first child node that has re­sults and then it of­fers them for au­to­com­ple­tion. Be­cause the search is UTF-8-aware, I had to take an ex­tra step to en­sure the au­to­com­ple­tion doesn’t have a trun­cat­ed se­quence at the end. So I wrote a small UTF-8 val­ida­tor in pure JavaScript. Was a fun side-quest 😊

OpenSearch brows­er in­te­gra­tion I’m a heavy us­er of brows­er’s search bar and search key short­cuts (for ex­am­ple, if I write cpp vector::emplace , my brows­er will search for std::vec­tor::em­place() di­rect­ly on cp­pref­er­ence.com). If you’re like me and want to have in-brows­er search avail­able al­so for Doxy­gen docs, it’s now dis­cov­er­able through OpenSearch on browsers that sup­port it. So, for ex­am­ple on Fire­fox, vis­it­ing doc.mag­num.graph­ics will of­fer you this: Chrome sup­ports OpenSearch as well, but the dis­cov­ery is well-hid­den deep in the set­tings — if you are on the doc­u­men­ta­tion site and open the search en­gine set­tings, it will sug­gest adding a new search en­gine. An­oth­er way that works in many browsers (al­so in Vi­val­di, for ex­am­ple) is right-click­ing the search field and se­lect­ing Add search en­gine. The un­der­ly­ing ca­pa­bil­i­ty that en­ables all this is recog­ni­tion of ?q={query}#search in GET pa­ram­e­ters. Ap­pend­ing it to the doc­u­men­ta­tion URL will di­rect­ly open a search pop­up with re­sults for {query} . OpenSearch al­so makes it pos­si­ble to show search re­sults and au­to­com­ple­tion di­rect­ly in the brows­er search bar (your brows­er might be al­ready us­ing this for Wikipedia, for ex­am­ple). While it would be nice to have, it un­for­tu­nate­ly needs a serv­er-side im­ple­men­ta­tion of the search. Be­cause doc.mag­num.graph­ics is cur­rent­ly just a min­i­mal file-serv­ing in­stal­la­tion and I’m not plan­ning to sup­port serv­er-side script­ing there (and thus hav­ing to deal with ad­di­tion­al se­cu­ri­ty is­sues) any time soon, I don’t have any im­me­di­ate rea­son to im­ple­ment this.

More good­ies Among oth­er things there’s now a sup­port for C++14 vari­able tem­plates and var­i­ous oth­er im­prove­ments, main­ly re­lat­ed to UX of the search pop­up. See the m.css com­mit his­to­ry if you want to know more. The theme is al­ways im­prov­ing, for a hint on what could come next, see for ex­am­ple mosra/m.css#79. If you want to get in­volved, there are var­i­ous is­sues marked help want­ed. I’m al­ways very hap­py to ac­cept con­tri­bu­tions, bu­gre­ports and sug­ges­tions for im­prove­ment — in par­tic­u­lar, it’s very pos­si­ble that the new fea­tures are bro­ken for cor­ner cas­es that I didn’t think about or that some things are not work­ing con­sis­tent­ly across all browsers. Com­ments on that very wel­come.