Improved Doxygen documentation and search

Wheth­er you are brows­ing Mag­num docs or use Doxy­gen for your own C++ doc­u­ment­a­tion, there’s al­ways a way to im­prove your work­flow. This art­icle presents the most re­cent ad­di­tions to the m.css Doxy­gen theme.

A year ago I switched Mag­num docs to a theme writ­ten en­tirely from scratch, adding a nev­er-be­fore-seen search func­tion­al­ity a while later. 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­lec­ted vari­ous en­hance­ment ideas and noted rough corners that need more pol­ish­ing, not to men­tion I re­ceived great feed­back from all the happy de­velopers that star­ted us­ing the theme for their own pro­jects or were merely the users of it through Mag­num doc­u­ment­a­tion.

Show­ing in­clude in­form­a­tion for all the things

A long-awaited — and I would say also the most im­port­ant — ad­di­tion is in­form­a­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 only for classes — which made sense for clas­sic OOP-heavy code­bases — it cer­tainly doesn’t help much in Mag­num, which has a lot of func­tion­al­ity dir­ectly in­side namespaces. While I’m try­ing hard to have the sym­bol ↔ file map­ping as in­tu­it­ive as pos­sible, it’s not al­ways clear and can be a lot of struggle es­pe­cially for new­comers.

So I went one step fur­ther and the doc­u­ment­a­tion now shows #include in­form­a­tion not only for classes, but also for namespaces (in case they are fully con­tained in a single head­er, such as An­im­a­tion::Eas­ing), for free func­tions, ty­pedefs, vari­ables and enums. That makes a big dif­fer­ence es­pe­cially in large namespaces such as Math or GL.

Include information for free namespace members

Pars­ing ad­di­tion­al func­tion at­trib­utes

Additional keywords

The theme was already hand­ling ex­tra at­trib­utes like deleted and defaulted func­tions and noexcept — which Doxy­gen is not re­cog­niz­ing at all, if I re­mem­ber cor­rectly. To com­plete this, now also override, final and con­di­tion­al noexcept are parsed and shown. Be­sides that, final is re­cog­nized also for classes, if you’d ever need that, and a few bugs re­lated to pars­ing of those at­trib­utes were fixed.

You can see these in ac­tion for ex­ample in Con­tain­ers::Op­tion­al.

Sup­port for doc­u­ment­ing private vir­tu­al func­tions

Documented private virtual functions

The clas­sic art­icle about Vir­tu­al­ity 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 private. That makes the in­ter­face design much more flex­ible and you don’t run in­to weird is­sues with co­v­ari­ant re­turn types.

Mag­num fol­lows this rule since the very be­gin­ning in its ap­plic­a­tion classes (such as Plat­form::Sdl2Ap­plic­a­tion) and all plu­gin in­ter­faces like Trade::Ab­strac­tIm­port­er, but un­til now Doxy­gen was not really able to show doc­u­mented private func­tions. To work around that, the private vir­tu­al func­tions used to be shown as protected, which was mis­lead­ing. Well, not any­more!

Im­proved or­der­ing for search res­ults

The ini­tial search im­ple­ment­a­tion as ex­plained in this art­icle was pick­ing up the res­ults in whatever or­der the search data had them in. This was already mil­lion times bet­ter and faster than the clas­sic Doxy­gen search im­ple­ment­a­tion, but later I real­ized it could be eas­ily im­proved to or­der the res­ults in a more use­ful way — in par­tic­u­lar pre­fer­ring classes and namespaces over func­tions and tuck­ing away de­prec­ated and deleted func­tion­al­ity, since you’re far less likely to need doc­u­ment­a­tion for these:

OpenSearch integration in Firefox
Search­ing for GL::Buf­fer be­fore
OpenSearch integration in Firefox
… and after

For­tu­nately, due to the way the search is im­ple­men­ted, this was only a mat­ter of sort­ing the res­ults while build­ing the search data, it re­quired no com­plex al­gorithm changes on the cli­ent side.

Auto­com­ple­tion in the search field

Be­sides the above, with fre­quent use it also be­came ap­par­ent that hav­ing to type long parts of sym­bol names to nar­row down the res­ults is … an­noy­ing. Again, a solu­tion was rather simple to im­ple­ment, mak­ing use of a prop­erty of the Trie search struc­ture — it col­lects char­ac­ters un­til the first child node that has res­ults and then it of­fers them for auto­com­ple­tion.

Search autocompletion

OpenSearch browser in­teg­ra­tion

I’m a heavy user of browser’s search bar and search key short­cuts (for ex­ample, if I write cpp vector::emplace, my browser will search for std::vec­tor::em­place() dir­ectly on cp­pref­er­en­ce.com). If you’re like me and want to have in-browser search avail­able also for Doxy­gen docs, it’s now dis­cov­er­able through OpenSearch on browsers that sup­port it. So, for ex­ample on Fire­fox, vis­it­ing doc.mag­num.graph­ics will of­fer you this:

OpenSearch integration in Firefox

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­ment­a­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 (also in Viv­aldi, for ex­ample) is right-click­ing the search field and se­lect­ing Add search en­gine.

The un­der­ly­ing cap­ab­il­ity that en­ables all this is re­cog­ni­tion of ?q={query}#search in GET para­met­ers. Ap­pend­ing it to the doc­u­ment­a­tion URL will dir­ectly open a search popup with res­ults for {query}.

More good­ies

Among oth­er things there’s now a sup­port for C++14 vari­able tem­plates and vari­ous oth­er im­prove­ments, mainly re­lated to UX of the search popup. See the m.css com­mit his­tory 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­ample mosra/m.css#79. If you want to get in­volved, there are vari­ous is­sues marked help wanted. I’m al­ways very happy 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­sible that the new fea­tures are broken for corner cases that I didn’t think about or that some things are not work­ing con­sist­ently across all browsers. Com­ments on that very wel­come.

Try it out

If you are a Mag­num user, there’s a chance you already spot­ted some of these im­prove­ments on doc.mag­num.graph­ics as I was gradu­ally push­ing them out. If you are us­ing Doxy­gen for your C++ docs, give the m.css Doxy­gen theme a go — I’m sure you’ll like the res­ult both as a lib­rary de­veloper and as an user of the doc­u­ment­a­tion 😊