Wikicode is inherently hard to read. It’s a mess of open braces, close braces, pipes, positional parameters to built-in parser functions, magic words, and “functions” (aka templates) whose logic is located on entirely separate pages. Whitespace, if you bother with it, has to be commented out. There’s so many special characters involved that you create templates named after one special character to print another. It’s a mess.
I’ve seen a lot of “tricks” over the years that people use to try to improve legibility of their wikicode. Some of them are:
- Put newlines at the start of every parser function argument (and comment them out)
- Put newlines in between every parser function (and comment them out)
- Indent every next level of parser function logic (and comment out the indentation)
In a remotely sane language, none of these things would be tricks; you would just do them. For this reason and many others, I suggest you turn to Extension:Scribunto and write Lua code whenever you’re doing anything complicated. But this article is not going to convince you why Lua is the best; instead, I’m going to show you this one trick that will save you 80% of your wikitext debugging time for 1/5 the effort of anything else!
(Note: All code in this post was originally written by me for Leaguepedia and is licensed under CC BY-SA 3.0.)
The one trick
Write a comment at the end of every parser function, template, etc, saying what you are ending.
Some examples
Here’s what I mean, from Template:PlayerResults, check out the <!-- end if -->
:
{{#invoke:PlayerResults|main|noredirects={{#if:{{NAMESPACE}}|yes}}<!-- end if -->}}{{#invoke:PlayerResults1v1|main}}
Or here, from Template:RosterChangePortalPeriod, with <!-- end vardefine -->
and <!-- endif -->
:
{{#vardefine:period|{{#titleparts:{{PAGENAME}}|1|2}}}}<!--
-->{{#ifeq:{{#var:period}}|Current|{{#vardefine:period|{{RosterSwapPortalCurrentPeriod}}<!-- end vardefine -->}}<!-- endif -->}}<!--
-->{{#var:period}}
Or here’s a more complicated example, from Template:GCDBackup. This one has <!-- end {{{diff|}} -->
, <!-- end vardefine -->
(twice), end if diff
, and end if isnew
- the comments for the last two are split across multiple lines:
{{#ifeq:{{#var:isnew}}|Yes|{{#if:{{#vardefineecho:diff|{{{diff|{{#dpl:|title={{#vardefineecho:currentpage|{{#titleparts:{{FULLPAGENAME}}|2|1}}/Current}}
|allrevisionssince={{#time:Y-m-d H:i|{{{pagecreationdate}}} {{{pagecreationtime}}} - 1 hour}}
|allrevisionsbefore={{#time:Y-m-d H:i|{{{pagecreationdate}}} {{{pagecreationtime}}} + 2 hours}}
|format=,%REVISION%
|debug=0
}}<!-- end {{{diff|}}} -->}}}<!-- end vardefine -->}}|Link to diff from previous version: <!--
-->{{#vardefineecho:diffurl|{{SERVER}}/index.php?title={{#replace:{{#var:currentpage}}| |_}}&type=revision&diff={{#var:diff}}<!-- end vardefine -->}}<br><!--
end if diff
-->}}<!--
end if isnew
-->}}
That last one could probably benefit from some indentation and maybe splitting that last long line up a bit (or, you know, rewriting it in Lua), but the commented “end” text is already doing us wonders for clarity.
Why does this help so much?
Hopefully you are already convinced just from seeing the examples above! If so, I’ll forgive you if you stop reading now & start doing this in your own templates :) But I’ll now explain why I think this technique is so effective.
It’s easier to work with than indentation
In a “sane” language (such as Lua! Use modules!), we would be afforded all of this at-a-glance pairing information of the starts and ends of code blocks by physical code blocks on the page where code is indented (Score one point for Python!). Because indentation is cumbersome in wikitext due to having to comment out the newlines - which makes automatic indentation almost impossible - a solution that can make your code more readable without requiring tons of commented newlines is desirable.
Indentation is also hard to change in a browser. If you decide to add or remove a clause, there is no select-all plus tab or shift-tab to automatically update it for you - and certainly there is no automatic format-all-code feature! An editor making a lot of changes is therefore likely to abandon careful indentation rules altogether out of frustration.
In contrast, code-block-ending comments can be written once and then left untouched until the code block is deleted or moved. Even better, they accustom the editor to writing comment blocks constantly, encouraging more widespread use of comments in wikitext. And while most of the time I would agree that “why, not how” comments are the way to go, given the nature of wikitext, you want to be leaving comments explaining both “why” and “how” your code works.
Rainbow Brackets
Rainbow Brackets is a popular code-highlighting package available in pretty much every popular text editor/IDE, including Sublime Text, PyCharm, and VSCode. It colors your nested pairs of matched braces, parentheses, brackets, and other grouping characters in rainbow order progressively outside-in, so that the outermost pair is red, then the next pair is orange, then yellow, etc. (The order is configurable, so if you prefer another order, you can set that as well.)
The result is that, in contrast to dynamically highlighting the pair of the current grouping character that your cursor is on top of, you instead have a static map showing you the total state of your pairs. This extra information is a huge improvement in seeing what is going on with your code. The price is performance of the text editor/IDE, and it does not transfer so well to MediaWiki, where (a) variably two or three braces at a time are used as an open/closed symbol; and (b) you are often editing in the browser, and so no (good) syntax highlighting is available (though of course, as always, you should use Mediawiker).
Instead of using Rainbow Brackets, we simply annotate our code with the information that this display could otherwise have provided us: the first set of open braces starts an #ifeq
so then we write <!-- end ifeq -->
by the final set of closing braces, and so forth.
HTML & XML actually do this
Markup languages like HTML and XML actually do use unique closing words - it’s <div>text goes here</div>
, not <div>text goes here</>
. Indeed, so do some programming languages such as VBA (If
…End If
, With
…End With
) and Bash (if
…fi
case
…esac
). (In Bash’s case…at least sometimes.) I’m not going to say either of those latter two is the pinnacle of legibility, but it’s not unheard of to consider something like <!-- endif -->
to be a part of a language.
Conclusion
The very first time I made a closing-block comment I said to myself “Huh, this seems kinda useful, but, damn, so much effort. I don’t think I’ll ever do this again.” But I’ve been doing it consistently ever since, any time I have more than two nested parser functions, parameters, or variables. I really hope you will try this out - do it at least ten times, come back to code that uses it at least a couple times, and see how much of a difference it makes! I’m thoroughly convinced you’ll find it worth the small effort it takes.